Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.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
如何通过不同的.net(c#)线程处理多个SQL事务_C#_.net_Database_Sqlbulkcopy_Sqltransaction - Fatal编程技术网

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

如何通过不同的.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

我使用以下方法在表中批量插入数据。 首先,我的代码填充数据表中的数据,并使用.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块中回滚事务时,后跟另一个异常

:执行活动时出错服务器无法恢复事务。描述: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();
            }
        }

如果我理解正确,您可以通过锁定数据库中的表来处理并发性。因此,只有一个线程有效地导入数据。那么为什么会有不同的线程呢?如果我理解正确,您可以通过锁定数据库中的一个表来处理并发性。因此,只有一个线程有效地导入数据。那么为什么会有不同的线程呢?无论如何,我认为在程序中处理并发性应该更有效,要么发送代码信号(使用互斥量或信号量),要么在线程池中执行此代码,而不使用表锁定,从而有效地同时执行导入。(我编辑之前的评论太慢了…抱歉)