Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# EF:在多个线程中更新相同的DB表行_C#_Multithreading_Entity Framework - Fatal编程技术网

C# EF:在多个线程中更新相同的DB表行

C# EF:在多个线程中更新相同的DB表行,c#,multithreading,entity-framework,C#,Multithreading,Entity Framework,我有一个教育任务,不明白我的代码中有什么错误。我正在尝试更新DB表并在事务中隔离此逻辑。最后,我陷入了僵局。有人能解释一下我做错了什么吗? 这里是我的线程创建逻辑: for (int i = 0; i < 10; i++) { var thread = new Thread(() => UpdateOrder(orderId)); threadList.Add(thread); thread.Start(); } foreach (var t in threa

我有一个教育任务,不明白我的代码中有什么错误。我正在尝试更新DB表并在事务中隔离此逻辑。最后,我陷入了僵局。有人能解释一下我做错了什么吗?
这里是我的线程创建逻辑:

for (int i = 0; i < 10; i++)
{
    var thread = new Thread(() => UpdateOrder(orderId));
    threadList.Add(thread);
    thread.Start();
}
foreach (var t in threadList)
{
    t.Join();
}
//Display sum by order items amount and amount property from order entity
WriteAmount(orderId);
我为每个线程创建了自己的上下文。为什么我的数据库检测到死锁?
这是异常消息:“事务(进程ID 51)在另一个进程的锁资源上被死锁,并且已被选为死锁牺牲品。请重新运行该事务。”

提前谢谢

您在数据库方面遇到了问题。 为什么要使用
IsolationLevel.RepeatableRead
事务类型?假设这就是原因。 您可以在此处了解不同的隔离级别:

我建议你: 1.将隔离级别更改为默认值
readcommitted

2.删除
order.Amount+=50。相反,在数据库端创建一个触发器来处理OrderItems表上的插入/更新/删除事件,并修改Orders表。

如果我设置了
IsolationLevel。RepeatableRead
按订单项计算的最终
Sum
当然不等于
Amount
属性。发生这种情况是因为您试图从并行事务计算它。因此,您正在尝试同时修改来自并行线程的相同数据。即使您很幸运,并且没有从数据库中获得事务死锁,您也会使用不正确的数据更新它。在读取订单金额和将该数字写入数据库(即使是两行连续的代码)之间,订单项目的数量可以更改,因此您需要触发器。它们是在DBMS中设计来维护数据一致性的,所以没有其他方法可以只使用数据库工具来解决多线程问题,对吗?也许我可以在桌子上锁上几排,对吗?嗯。。。有很多方法可以做到这一点。。。在mssql中,您可以使用类似的方法,或者您可以使用Redis提供跨进程锁或e.t.c.或者您可以为每个订单创建一个对象字典,并使用
lock
语句来防止对同一订单进行并行处理(但如果您从其他进程或其他方法更新订单,这将失败),但是,从我的角度来看,像这样的一切都有点像直肠。谢谢你的重播。但是我只需要用DB工具来解决这个问题。我已经阅读了updlock和rowlock的相关内容,现在正在考虑如何在当前情况下使用它们。可能是因为所有上下文和事务都需要OrderItems表上的writelock,并且在读取操作完成之前都不会释放其锁。这将导致9个上下文出现死锁-它根本不适用于2PL。另外,请记住DbContext不是线程安全的——在多线程环境中使用它时,不能期望它能够完美地工作。
public static void UpdateOrder(int orderId)
{
    using (var db = new OrderContext()
    {
        using (var transactionScope = new TransactionScope(TransactionScopeOption.RequiresNew
            ,new TransactionOptions { IsolationLevel = IsolationLevel.RepeatableRead }))
        {
            var o1 = new OrderItem { Title = "title", Amount = 50, Count = 1, OrderId = orderId };
            db.OrderItems.Add(o1);
            var order = db.Orders.Find(orderId); //Include(o => o.Items).Single(o => o.Id == orderId);
            order.Amount += 50; //order.Items.Sum(oi => oi.Amount);
            db.SaveChanges();
            transactionScope.Complete();
        }
    }
}