Entity Framework 事务和死锁
Entity Framework Transactions and Deadlock
在上下文中调用 SaveChanges() 时,所有 insert/delete/update 操作都在单个事务中执行。也可以将 DbContextTransaction 用于事务。我正在尝试使用这两种方法来模拟死锁。当我使用 DbContextTransaction 时,我立即得到死锁异常,但单独的 SaveChanges() 即使在一小时后也不会抛出任何死锁异常。我做错了什么吗?
这里是 DbContextTransaction 的代码。我尝试更新主线程中的第一行,然后是第二行。我还开始了另一个任务,尝试先更新第二行,然后再更新第一行。
while (true)
{
using (var context = new SchoolDBEntities())
{
using (System.Data.Entity.DbContextTransaction dbTran = context.Database.BeginTransaction())
{
Random r = new Random();
int r1 = r.Next();
int r2 = r.Next();
Student std1 = context.Students.First();
std1.StudentName = "test"+r1;
context.SaveChanges();
Student std2 = context.Students.Find(2);
std2.StudentName = "test"+r2;
context.SaveChanges();
dbTran.Commit();
}
}
}
但是当我尝试仅使用 SaveChanges() 时,它不会产生死锁:
while (true)
{
using (var context = new SchoolDBEntities())
{
try
{
Random r = new Random();
int r1 = r.Next();
int r2 = r.Next();
Student std1 = context.Students.First();
std1.StudentName = "test" + r1;
Student std2 = context.Students.Find(2);
std2.StudentName = "test" + r2;
context.SaveChanges();
}
}
}
我正在使用 SQL Profiler 来跟踪交易。我什至对第二种方法添加了更多更新,只是为了使该事务的持续时间等于 DbContextTransaction 案例,认为这可能是原因,但仍然没有运气!当我查看跟踪时,我看到属于特定事务的更新仅在前一个事务提交后才开始。可能是什么原因?
经过进一步调查,我发现无论我在上下文中所做的更改顺序如何,SaveChanges() 方法始终向 SQL 服务器发送更新查询的顺序是基于table 的主键。换句话说,即使我尝试通过先更改第 2 行然后更改第 1 行来颠倒更新请求的顺序,SaveChanges() 首先对第 1 行然后对第 2 行执行更新查询。这就是为什么我没有得到通过仅使用 SaveChanges() 方法来避免死锁。它不会颠倒查询的顺序。
在上下文中调用 SaveChanges() 时,所有 insert/delete/update 操作都在单个事务中执行。也可以将 DbContextTransaction 用于事务。我正在尝试使用这两种方法来模拟死锁。当我使用 DbContextTransaction 时,我立即得到死锁异常,但单独的 SaveChanges() 即使在一小时后也不会抛出任何死锁异常。我做错了什么吗?
这里是 DbContextTransaction 的代码。我尝试更新主线程中的第一行,然后是第二行。我还开始了另一个任务,尝试先更新第二行,然后再更新第一行。
while (true)
{
using (var context = new SchoolDBEntities())
{
using (System.Data.Entity.DbContextTransaction dbTran = context.Database.BeginTransaction())
{
Random r = new Random();
int r1 = r.Next();
int r2 = r.Next();
Student std1 = context.Students.First();
std1.StudentName = "test"+r1;
context.SaveChanges();
Student std2 = context.Students.Find(2);
std2.StudentName = "test"+r2;
context.SaveChanges();
dbTran.Commit();
}
}
}
但是当我尝试仅使用 SaveChanges() 时,它不会产生死锁:
while (true)
{
using (var context = new SchoolDBEntities())
{
try
{
Random r = new Random();
int r1 = r.Next();
int r2 = r.Next();
Student std1 = context.Students.First();
std1.StudentName = "test" + r1;
Student std2 = context.Students.Find(2);
std2.StudentName = "test" + r2;
context.SaveChanges();
}
}
}
我正在使用 SQL Profiler 来跟踪交易。我什至对第二种方法添加了更多更新,只是为了使该事务的持续时间等于 DbContextTransaction 案例,认为这可能是原因,但仍然没有运气!当我查看跟踪时,我看到属于特定事务的更新仅在前一个事务提交后才开始。可能是什么原因?
经过进一步调查,我发现无论我在上下文中所做的更改顺序如何,SaveChanges() 方法始终向 SQL 服务器发送更新查询的顺序是基于table 的主键。换句话说,即使我尝试通过先更改第 2 行然后更改第 1 行来颠倒更新请求的顺序,SaveChanges() 首先对第 1 行然后对第 2 行执行更新查询。这就是为什么我没有得到通过仅使用 SaveChanges() 方法来避免死锁。它不会颠倒查询的顺序。