Entity Framework (6) 单次和多次 SaveChanges() 调用的交易有什么区别
What's the difference between Entity Framework (6) transactions with single and multiple SaveChanges() calls
我想知道这三种方式在同一数据库上下文中执行事务的实际区别是什么:
1) 一次 SaveChanges()
的多项操作,没有明确使用 sql 事务
using (TestDbContext db = new TestDbContext())
{
// first operation
// second operation
db.SaveChanges();
}
2) 使用 sql 事务
一次 SaveChanges()
进行多项操作
using (TestDbContext db = new TestDbContext())
using (DbContextTransaction trans = db.Database.BeginTransaction())
{
// operation 1
// operation 2
db.SaveChanges();
trans.commit();
}
3) 多个 SaveChanges()
的操作,使用 sql 事务
using (TestDbContext db = new TestDbContext())
using (DbContextTransaction trans = db.BeginTransaction())
{
// operation 1
db.SaveChanges();
// operation 2
db.SaveChanges();
trans.commit();
}
在(2)和(3)中,如果commit()
应该实际执行请求的sql对数据库的查询,它真的不同吗,比如说,为每个操作保存更改或保存更改一次进行所有操作?
而if(1)也可以让多个操作在同一个数据库上下文中安全执行那么手动启动事务的主要用途是什么?我想说我们可以手动提供 try/catch 块以在发生不良情况时回滚事务,但据我所知,SaveChanges() 也会自动覆盖它,至少在 SQLServer 中是这样。
** 更新:另一件事是:我应该将数据库上下文和事务变量设置为 class 级别,还是应该仅包含方法的本地变量?
如果不启动事务,则为隐式。意思是,您执行的所有 SaveChanges()
将在调用后立即在数据库中可用。
如果您启动一个事务,SaveChanges()
仍会执行更新,但在调用 commit
之前数据对其他连接不可用。
您可以通过设置断点、创建新对象、将它们添加到上下文并执行 SaveChanges()
来自行测试。您会看到 ID 属性 在该调用后将具有一个值,但在您对事务执行提交之前,数据库中不会有相应的行。
就您的第二个问题而言,这实际上取决于并发需求、您的 class 正在做什么以及您正在处理多少数据。这与其说是一个范围问题,不如说是一个代码执行问题。
上下文不是线程安全的,因此只要您的应用程序中只有一个线程访问上下文,您就可以在更广泛的范围内使用它。但是,如果应用程序的其他实例正在访问数据,您将必须确保将数据刷新到最新模型。您还应该考虑到,加载到内存中的模型越多,随着时间的推移,保存速度就越慢。
我倾向于创建尽可能接近要执行的操作的上下文,并在之后尽快处理它们。
您的问题似乎根本不是关于 entity framework,而是关于 sql 交易。 sql 事务是单个 'atomic' 更改。也就是说,要么提交所有更改,要么提交 none。
您并没有真正涵盖该场景的示例,但如果您添加另一个示例,例如:
using (TestDbContext db = new TestDbContext())
{
// operation 1
db.SaveChanges();
// operation 2
db.SaveChanges();
}
...在此示例中,如果您的第一个操作成功保存,但第二个操作失败,您可能会遇到第一步提交的数据可能无效的情况。
这就是为什么您会使用 sql 事务,将两个 SaveChanges
包装到一个操作中,这意味着 所有 数据都已提交,或者 none 已提交。
我想知道这三种方式在同一数据库上下文中执行事务的实际区别是什么:
1) 一次 SaveChanges()
的多项操作,没有明确使用 sql 事务
using (TestDbContext db = new TestDbContext())
{
// first operation
// second operation
db.SaveChanges();
}
2) 使用 sql 事务
一次SaveChanges()
进行多项操作
using (TestDbContext db = new TestDbContext())
using (DbContextTransaction trans = db.Database.BeginTransaction())
{
// operation 1
// operation 2
db.SaveChanges();
trans.commit();
}
3) 多个 SaveChanges()
的操作,使用 sql 事务
using (TestDbContext db = new TestDbContext())
using (DbContextTransaction trans = db.BeginTransaction())
{
// operation 1
db.SaveChanges();
// operation 2
db.SaveChanges();
trans.commit();
}
在(2)和(3)中,如果commit()
应该实际执行请求的sql对数据库的查询,它真的不同吗,比如说,为每个操作保存更改或保存更改一次进行所有操作?
而if(1)也可以让多个操作在同一个数据库上下文中安全执行那么手动启动事务的主要用途是什么?我想说我们可以手动提供 try/catch 块以在发生不良情况时回滚事务,但据我所知,SaveChanges() 也会自动覆盖它,至少在 SQLServer 中是这样。
** 更新:另一件事是:我应该将数据库上下文和事务变量设置为 class 级别,还是应该仅包含方法的本地变量?
如果不启动事务,则为隐式。意思是,您执行的所有 SaveChanges()
将在调用后立即在数据库中可用。
如果您启动一个事务,SaveChanges()
仍会执行更新,但在调用 commit
之前数据对其他连接不可用。
您可以通过设置断点、创建新对象、将它们添加到上下文并执行 SaveChanges()
来自行测试。您会看到 ID 属性 在该调用后将具有一个值,但在您对事务执行提交之前,数据库中不会有相应的行。
就您的第二个问题而言,这实际上取决于并发需求、您的 class 正在做什么以及您正在处理多少数据。这与其说是一个范围问题,不如说是一个代码执行问题。
上下文不是线程安全的,因此只要您的应用程序中只有一个线程访问上下文,您就可以在更广泛的范围内使用它。但是,如果应用程序的其他实例正在访问数据,您将必须确保将数据刷新到最新模型。您还应该考虑到,加载到内存中的模型越多,随着时间的推移,保存速度就越慢。
我倾向于创建尽可能接近要执行的操作的上下文,并在之后尽快处理它们。
您的问题似乎根本不是关于 entity framework,而是关于 sql 交易。 sql 事务是单个 'atomic' 更改。也就是说,要么提交所有更改,要么提交 none。
您并没有真正涵盖该场景的示例,但如果您添加另一个示例,例如:
using (TestDbContext db = new TestDbContext())
{
// operation 1
db.SaveChanges();
// operation 2
db.SaveChanges();
}
...在此示例中,如果您的第一个操作成功保存,但第二个操作失败,您可能会遇到第一步提交的数据可能无效的情况。
这就是为什么您会使用 sql 事务,将两个 SaveChanges
包装到一个操作中,这意味着 所有 数据都已提交,或者 none 已提交。