Parallel.ForEach中的SQL查询-死锁

本文关键字:死锁 查询 SQL ForEach 中的 Parallel | 更新日期: 2023-09-27 17:58:14

我有一个静态方法,它在Parallel.ForEach循环中的静态方法内部调用SQL SP。SP在3个不同的表中插入数据。我正在使用可序列化事务级别。但偶尔我会陷入僵局。

我认为,如果我将该方法作为Instance方法或使用简单的ForEach,它可能会解决问题。

我想得对吗?我也需要锁定列表吗?

--代码——

Parallel.ForEach(MyConcurrentDictionary, MyElement =>
{
   if (MyElement.SomeProperty != SomeValue)
      {
         PublishMessage(MyElement);
      }
      else
      {
         InsertInDatabase(MyElement);
      }
}


public static void InsertInDatabase()
{
   DataTable t1 = new DataTable();
   DataTable t2 = new DataTable();
   DataTable t3 = new DataTable();

   CreateTable(T1);
   CreateTable(T2);
   CreateTable(T3);
   using (var conn = new SqlConnection(ConnString))
      {
         try
            {
               conn.Open();
               // Begin transaction
               using (SqlTransaction transaction = conn.BeginTransaction(IsolationLevel.Serializable))
                  {
                     SqlCommand cmd = new SqlCommand();
                     cmd.Transaction = transaction;
                     cmd.Connection = conn;
                     cmd.CommandType = CommandType.StoredProcedure;
                     cmd.CommandText = "SPName";
                     cmd.Parameters.AddWithValue("@T1", T1);
                     cmd.Parameters.AddWithValue("@T2", T2);
                     cmd.Parameters.AddWithValue("@T3", T3);
                     cmd.ExecuteNonQuery();
                     transaction.Commit();
                }
           }
     }
}

Parallel.ForEach中的SQL查询-死锁

尝试将类更改为非静态方法,这将有很大帮助。永远不要并行使用静力学——这只是在找麻烦。为了安全起见,请尝试使用线程保存列表,也称为同步数组列表或System.Collections.Concurrent.ConcurrentQueue(Of T)

亲切问候

您会遇到问题,因为您没有使用任何同步。关键字static并不意味着它是线程安全的。来自Parallel.ForEach的多个线程仍然可以同时访问此方法。

你有很多选择来同步它。但我将从最简单的一个开始,使其成为单线程。如果不可能,请使用lock或查看其他选项

更新
正如@Colin所注意到的,如果你在某个地方更新数据,我的答案是有效的。如果所有内容都是只读的,那么还有其他内容。检查DataTable的创建情况。