如何通过不同的.net(c#)线程处理多个SQL事务

.net c# database sqlbulkcopy sqltransaction

我有以下方法来批量插入表中的数据。首先,我的代码填充数据表中的数据,并使用.net的SqlBulkCopy claas将此数据插入相应的表中。

我要求数据应插入所有表中,或者都不插入。为此,我使用了.net的SqlTransaction类。

场景是,多个线程同时执行以下代码块。

 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块中回滚事务

:错误执行活动时服务器无法恢复事务。说明:3a00000001。此会话中活动的事务已由另一个会话提交或中止。

任何人都可以帮助我解决这个奇怪的代码行为。我已经在互联网上搜索了很多这个问题,但我没有找到任何对我有用的东西。

一般承认的答案

我的问题解决了。

以下是我对Import方法所做的更改

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();
            }
        }

热门答案

在导入(DataTables中的DataTable dt)不是线程安全的。

sqlConnection已经有一个来自Import的活动阅读器,因此无法在ImportIntoDatabase中使用该连接。

Echo smp - 如果你锁定一个表然后为什么多线程?

如果要在SQL插入发生时构建输入,请使用Asynch方法,如SqlCommand.BeginExecuteReader。你得到asynch没有一个线程的开销。而DataTables相对较慢。我使用TVP和轻量级物体插入。插入性能的一个重要因素是索引碎片。如果可能的话,按聚簇索引的顺序插入顺序。循环是简单的构建输入,等待异步,运行asych。或者可以从队列中读取构建输入。对同一个表的SQL插入通常不会更快并行。我的经验是订购连续插件,插件之间没有时间间隔。




许可下: CC-BY-SA with attribution
不隶属于 Stack Overflow
这个KB合法吗? 是的,了解原因
许可下: CC-BY-SA with attribution
不隶属于 Stack Overflow
这个KB合法吗? 是的,了解原因