运行多个线程时 SQL 事务发生内部连接致命错误

Posted

技术标签:

【中文标题】运行多个线程时 SQL 事务发生内部连接致命错误【英文标题】:Internal connection fatal error on SQL Transaction when running multiple threads 【发布时间】:2021-10-19 02:12:30 【问题描述】:

我正在编写一个应用程序,它同时对某些设备进行多项测试。 测试后我想将结果添加到数据库中。 我在数据库中有 3 个表:Testsequence、Maintest、Subtest 要链接数据,我必须知道“父”表对象的 id

但是当我运行超过 1 个任务时,我得到:"Internal connection fatal error." on sequenceId = Convert.ToInt32(sqlcommand.ExecuteScalar());

目前我正在使用带有 Microsoft SQL Server 的本地数据库(使用 System.Data.SqlClient;)

public static void AddResults(Device device)
    
        using (var connection = new SqlConnection(Settings.DBConnectionString))
        
            SqlTransaction transaction;
            transaction = _sqlConnection.BeginTransaction(IsolationLevel.ReadCommitted);

            try
            
                SqlCommand sqlcommand = _sqlConnection.CreateCommand();
                sqlcommand.Connection = _sqlConnection;
                sqlcommand.Transaction = transaction;

                // Add Testsequence
                sqlcommand = new SqlCommand(@"INSERT INTO TestSequence (IdMachine,DateTime) VALUES (@IdDevice,@DateTime) SELECT SCOPE_IDENTITY()", _sqlConnection, transaction);
                
                    sqlcommand.Parameters.Add(new SqlParameter("@IdDevice", device.DataBaseId));
                    sqlcommand.Parameters.Add(new SqlParameter("@DateTime", device.Progress.ResultActive.Time));
                
                sequenceId = Convert.ToInt32(sqlcommand.ExecuteScalar());

                foreach (TestCategory category in device.Progress.ResultActive)
                
                    foreach (MainTest mainTest in category)
                    
                        // Add MainTest
                        if (mainTest.Time == null) continue;
                        sqlcommand = new SqlCommand(@"INSERT INTO MainTests (IdSequenceMT,IdTestNameMT,DateTimeMT,Passed) VALUES @IdSequenceMT,@IdTestNameMT,@DateTimeMT,@Passed) SELECT SCOPE_IDENTITY()", _sqlConnection, transaction);
                        
                            sqlcommand.Parameters.Add(new SqlParameter("@IdSequenceMT", sequenceId));
                            sqlcommand.Parameters.Add(new SqlParameter("@IdTestNameMT", mainTest.Id));
                            sqlcommand.Parameters.Add(new SqlParameter("@DateTimeMT", mainTest.Time));
                            sqlcommand.Parameters.Add(new SqlParameter("@Passed", mainTest.Pass));
                        
                        mainTestId = Convert.ToInt32(sqlcommand.ExecuteScalar());

                        foreach (SubTest subTest in mainTest)
                        
                            // Add SubTest
                            if (subTest.Pass == null) continue;
                            sqlcommand = new SqlCommand(@"INSERT INTO SubTests
                            (IdMainTestST,IdTestName,DateTimeST,Passed,Log_enUS,Log_deDE) VALUES (@IdMainTestST,@IdTestName,@DateTimeST,@Passed,@Log_enUS,@Log_deDE)",
                                _sqlConnection, transaction);
                            
                                sqlcommand.Parameters.Add(new SqlParameter("@IdMainTestST", mainTestId));
                                sqlcommand.Parameters.Add(new SqlParameter("@IdTestName", subTest.Id));
                                sqlcommand.Parameters.Add(new SqlParameter("@DateTimeST", subTest.Time));
                                sqlcommand.Parameters.Add(new SqlParameter("@Passed", subTest.Pass));
                                sqlcommand.Parameters.Add(new SqlParameter("@Log_enUS", subTest.Log));
                                sqlcommand.Parameters.Add(new SqlParameter("@Log_deDE", subTest.Log));
                            
                            sqlcommand.ExecuteNonQuery();
                        
                    
                
                if (connection.State != System.Data.ConnectionState.Open) connection.Open();
                transaction.Commit();
                log.Info($"SQL device.Serialnumber|device.DataBaseId: Testsequence Id: sequenceId added");
            
            catch (Exception e)
            
                transaction.Rollback();
                log.Info($"SQL : device.Serialnumber Testsequence add: transaction rollback\ne");
                Helper.UiMessage($"device.Serialnumber Project.Properties.Resources.results_not_added", 60);
            
        
    

我尝试了什么:

在我有一个用于连接的全局变量之前......这不是问题 我没有使用 using 语句...无论如何这也不是问题

也许你看到我的代码不是最好的 :D 如果你有任何其他改进的想法,也请写评论。

我也不知道问题出在多线程、查询命令还是事务中多个命令的执行。

提前致谢:)

【问题讨论】:

请标记您的 DBMS 据我了解,事务是将“更多查询”放在一批中以传输到服务器 => 我想保持网络流量尽可能低。如果我只能使用单个命令,我该如何重写我的代码......以及为什么它在使用单个设备执行时可以工作?我还需要在下一个命令中使用的父级 => Scope_identity 的 id... 您仍在使用您的全局_sqlConnection 创建事务并执行命令。将其切换到局部变量connectiontransaction 也应该在 using 中。另见***.com/questions/17552829/… try 之后的前三行似乎毫无意义,因为sqlCommand 已被覆盖。事务不会降低网络流量,它们确保以原子方式生成一组语句。为了尽量减少流量,更重要的是让它表现得更好,您可以使用表值参数进行批量插入 【参考方案1】:

...问题就在屏幕前...-.-

旧的 _sqlConnection 是之前“版本”的遗留物。

将 _sqlConnection 更改为连接 添加了缺少的交易使用语句

感谢@Charlieface

【讨论】:

以上是关于运行多个线程时 SQL 事务发生内部连接致命错误的主要内容,如果未能解决你的问题,请参考以下文章

连接sql server2005时提示:内部连接致命错误。

游戏更新就出现发生致命错误Win32Error怎么回事

SQL SERVER中,多个事物间同是并发操作数据时,会发生事务之间数据读取不一致的 情况,

C# 中连接SQLServer 出现内部致命错误

创建 TLS 客户端凭据时发生致命错误。内部错误状态为 10013

XACT_ABORT为默认为off事务发生约束性错误会继续运行,为on发生约束性错误时会rollback