如何通过不同的.net(c#)线程处理多个SQL事务
我使用以下方法在表中批量插入数据。 首先,我的代码填充数据表中的数据,并使用.net的SqlBulkCopy claas将这些数据插入相应的表中 我有一个要求,数据应该被插入到所有的表中,或者两者都不插入。 为此,我使用了.net的SqlTransaction类 场景是,多个线程同时执行以下代码块如何通过不同的.net(c#)线程处理多个SQL事务,c#,.net,database,sqlbulkcopy,sqltransaction,C#,.net,Database,Sqlbulkcopy,Sqltransaction,我使用以下方法在表中批量插入数据。 首先,我的代码填充数据表中的数据,并使用.net的SqlBulkCopy claas将这些数据插入相应的表中 我有一个要求,数据应该被插入到所有的表中,或者两者都不插入。 为此,我使用了.net的SqlTransaction类 场景是,多个线程同时执行以下代码块 public void Import() { using (SqlConnection sqlConnection = new SqlConnection(c
public void Import()
{
using (SqlConnection sqlConnection = new SqlConnection(connectionString))
{
SqlTransaction sqlTrans =null;
try
{
sqlConnection.Open();
sqlTrans = sqlConnection.BeginTransaction(IsolationLevel.Serializable)
SqlCommand cmd = sqlConnection.CreateCommand();
cmd.CommandText = "select top 1 null from lockTable with(xlock)";
cmd.CommandTimeout = 3600*3;
cmd.Transaction = sqlTrans;
SqlDataReader reader = cmd.ExecuteReader();
foreach (DataTable dt in DataTables)
{
ImportIntoDatabase(sqlConnection, dt, sqlTrans);
}
reader.Close();
sqlTrans.Commit();
}
catch (Exception ex)
{
sqlTrans.Rollback();
throw ex;
}
}
}
private void ImportIntoDatabase(SqlConnection sqlConn, DataTable dt, SqlTransaction sqlTrans)
{
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(sqlConn, SqlBulkCopyOptions.Default, sqlTrans))
{
bulkCopy.BulkCopyTimeout = dt.Rows.Count * 10;
try
{
bulkCopy.DestinationTableName = dt.TableName;
bulkCopy.WriteToServer(dt);
}
catch (Exception ex)
{
throw ex;
}
}
}
为了处理这种并发性,我在另一个表(大容量插入表)所在的数据库中创建了一个虚拟表(名为“lockTable”的表)。我在SqlTransaction中获得了这个虚拟表的独占锁,命令超时高达3小时
问题:
我得到了以下例外
:无法访问目标表“Tbl1”(Tbl1是用于批量插入的表)
在catch块中回滚事务时,后跟另一个异常
:执行活动时出错服务器无法恢复事务。描述:310000001。
此会话中活动的事务已由另一个会话提交或中止
有人能帮我解决这个奇怪的代码行为吗。我已经在互联网上搜索了很多关于这个问题的内容,但是我没有找到任何对我有用的东西。如果多个线程都可以访问“导入”方法,那么你不应该锁定这个方法的内容吗 我不认为您需要一个虚拟表,您只需要锁定上面的两个方法 我还要提到的是,您应该加入所有线程,这样您就可以知道它们何时完成了。导入中(DataTable中的DataTable dt)将不是线程安全的 sqlConnection已具有来自导入的活动读取器,因此无法在ImportIntoDatabase中使用该连接 Echo smp-如果要锁定表,为什么要锁定多线程 如果您想在SQL插入发生时建立输入,那么使用
异步方法,如SqlCommand.BeginExecuteReader。您可以在没有线程开销的情况下获得异步。数据表的速度相对较慢。我使用TVP和轻型对象插入。影响插入性能的一个重要因素是索引碎片。如果可能,请按聚集索引的顺序插入顺序。循环是简单的构建输入,等待asynch,运行asynch。或生成输入可以是队列中的读取输入。对同一个表的SQL插入通常不会以并行方式更快。我的经验是订购串行插入,插入之间没有时间间隔。我的问题解决了 以下是我对导入方法所做的更改
public void Import()
{
using (SqlConnection sqlConnection = new SqlConnection(connectionString))
{
sqlConnection.Open();
using (SqlTransaction sqlTrans = sqlConnection.BeginTransaction())
{
try
{
SqlCommand cmd = sqlConnection.CreateCommand();
cmd.CommandText = "select top 1 null from lockTable with(xlock)";
cmd.CommandTimeout = LOCK_TIME_OUT;
cmd.Transaction = sqlTrans;
SqlDataReader reader = cmd.ExecuteReader();
foreach (DataTable dt in DataTables)
{
ImportIntoDatabase(sqlConnection, dt, sqlTrans);
}
reader.Close();
sqlTrans.Commit();
}
catch (Exception ex)
{
sqlTrans.Rollback();
throw ex;
}
}
sqlConnection.Close();
}
}
如果我理解正确,您可以通过锁定数据库中的表来处理并发性。因此,只有一个线程有效地导入数据。那么为什么会有不同的线程呢?如果我理解正确,您可以通过锁定数据库中的一个表来处理并发性。因此,只有一个线程有效地导入数据。那么为什么会有不同的线程呢?无论如何,我认为在程序中处理并发性应该更有效,要么发送代码信号(使用互斥量或信号量),要么在线程池中执行此代码,而不使用表锁定,从而有效地同时执行导入。(我编辑之前的评论太慢了…抱歉)