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();
}
}
}
}
尝试将类更改为非静态方法,这将有很大帮助。永远不要并行使用静力学——这只是在找麻烦。为了安全起见,请尝试使用线程保存列表,也称为同步数组列表或System.Collections.Concurrent.ConcurrentQueue(Of T)
。
亲切问候
您会遇到问题,因为您没有使用任何同步。关键字static
并不意味着它是线程安全的。来自Parallel.ForEach
的多个线程仍然可以同时访问此方法。
你有很多选择来同步它。但我将从最简单的一个开始,使其成为单线程。如果不可能,请使用lock
或查看其他选项
更新
正如@Colin所注意到的,如果你在某个地方更新数据,我的答案是有效的。如果所有内容都是只读的,那么还有其他内容。检查DataTable的创建情况。