我想知道在这三种方式之间在同一数据库环境中执行事务的实用差异是什么:
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)使用sql事务
进行多个SaveChanges()
的多个操作
using (TestDbContext db = new TestDbContext())
using (DbContextTransaction trans = db.BeginTransaction())
{
// operation 1
db.SaveChanges();
// operation 2
db.SaveChanges();
trans.commit();
}
在(2)和(3)中,如果commit()
应该实际执行对数据库的请求的sql查询,是否真的不同,比如保存每个操作的更改或保存所有操作的更改?
如果(1)还可以允许在同一个数据库上下文中安全地执行多个操作,那么手动启动事务的主要用途是什么?我说我们可以手动提供try / catch块以在发生错误时回滚事务,但AFAIK,SaveChanges()也会自动覆盖它,至少是SQLServer。
**更新:另一件事是:我应该将数据库上下文和事务变量设置为类级别,还是应该只包含方法本地?
答案 0 :(得分:3)
如果您不启动交易,则隐含。这意味着,您执行的所有SaveChanges()
将在调用后立即在数据库中可用。
如果您开始交易,SaveChanges()
仍会执行更新,但在调用commit
之前,其他连接无法使用这些数据。
您可以通过设置断点,创建新对象,将其添加到上下文以及执行SaveChanges()
来自行测试。您将看到ID属性在该调用之后将具有值,但在您对事务执行提交之前,数据库中将没有相应的行。
就您的第二个问题而言,它实际上取决于并发需求,您的课程正在做什么以及您正在使用多少数据。这不是一个范围问题,而是一个代码执行问题。
上下文不是线程安全的,因此只要您的应用程序中只有一个线程访问上下文,就可以在更广泛的范围内实现。但是,如果应用程序的其他实例正在访问数据,则您必须确保将数据刷新到最新模型。您还应该考虑到已经加载到内存中的模型越多,随着时间的推移,速度就越慢。
我倾向于创建我的上下文,尽可能接近要执行的操作,并在不久之后处理它们。
答案 1 :(得分:2)
你的问题根本就不是关于实体框架的问题,更多的是关于sql事务。一个sql事务是一个单一的原子'更改。也就是说,所有更改都已提交,或者都没有提交。
您还没有一个涵盖该方案的示例,但如果您添加了另一个示例,例如:
using (TestDbContext db = new TestDbContext())
{
// operation 1
db.SaveChanges();
// operation 2
db.SaveChanges();
}
...在此示例中,如果您的第一个操作成功保存,但第二个操作失败,则可能会出现第一步提交的数据可能无效的情况。
这就是为什么你要使用sql事务,将SaveChanges
包装到单个操作中,这意味着提交所有数据,或者 none 承诺。