CREATE / ALTER / PRINT之后出现System.Data.SqlClient.SqlException

问题描述

我来自另外两个问题,试图了解为什么会发生此异常。

Entity Framework seed -> SqlException: Resetting the connection results in a different state than the initial login. The login fails. 差异化结果

What does "Resetting the connection" mean? System.Data.SqlClient.SqlException (0x80131904)

代码重现异常。

string dbname = "TESTDB";
Run("master",$"CREATE DATABASE [{dbname}]");
Run(dbname,$"ALTER DATABASE [{dbname}] COLLATE latin1_General_100_CI_AS");
Run(dbname,"PRINT 'HELLO'");

void Run(string catalog,string script)
{
    var cnxStr = new sqlConnectionStringBuilder
    {
        DataSource = serverAndInstance,UserID = user,Password = password,InitialCatalog = catalog
    };

    using var cn = new sqlConnection(cnxStr.ToString());
    using var cm = cn.CreateCommand();
    cn.open();
    cm.CommandText = script;
    cm.ExecuteNonQuery();
}

完整的堆栈跟踪为

Unhandled Exception: System.Data.sqlClient.sqlException: Resetting the connection results in a different state than the initial login. The login fails.
Login Failed for user 'user'.
Cannot continue the execution because the session is in the kill state.
A severe error occurred on the current command.  The results,if any,should be discarded.
   at System.Data.sqlClient.sqlConnection.OnError(sqlException exception,Boolean breakConnection,Action`1 wrapCloseInAction)
   at System.Data.sqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj,Boolean callerHasConnectionLock,Boolean asyncclose)
   at System.Data.sqlClient.TdsParser.TryRun(RunBehavior runBehavior,sqlCommand cmdHandler,sqlDataReader dataStream,BulkcopySimpleResultSet bulkcopyHandler,TdsParserStateObject stateObj,Boolean& dataReady)
   at System.Data.sqlClient.sqlCommand.RunExecuteNonQueryTds(String methodName,Boolean async,Int32 timeout,Boolean asyncWrite)
   at System.Data.sqlClient.sqlCommand.InternalExecuteNonQuery(taskcompletionsource`1 completion,String methodName,Boolean sendToPipe,Boolean& usedCache,Boolean asyncWrite,Boolean inRetry)
   at System.Data.sqlClient.sqlCommand.ExecuteNonQuery()
...

如果我将第一个Run(dbname...更改为Run("master"...,它将运行正常。 因此,这与在同一数据库的上下文中运行ALTER DATABASE有关

“重置连接”是什么意思? 会话为何处于“ kill状态”。 ? 我应该避免在同一数据库中运行“ ALTER”语句吗?为什么?

解决方法

错误“重置连接将导致状态不同于初始登录。登录失败。”是由于pooled connection在数据库状态更改(数据库排序规则更改)之后被重用。以下是内部导致错误的情况。

此代码运行时:

Run(dbName,$"ALTER DATABASE [{dbName}] COLLATE Latin1_General_100_CI_AS");

ADO.NET通过匹配连接字符串和安全上下文来查找现有的池连接。未找到任何内容,因为现有池化连接(来自CREATE DATABASE查询)的连接字符串不同(master数据库而不是TESTDB)。 ADO.NET然后创建一个新连接,其中包括建立TCP / IP连接,身份验证和SQL Server会话初始化。 ALTER DATABASE查询在此新连接上运行。连接处理后(超出using范围),该连接将添加到连接池中。

然后运行:

Run(dbName,"PRINT 'HELLO'");

ADO.NET查找现有的池TESTDB连接,并使用该连接代替实例化新连接。当PRINT命令发送到SQL Server时,TDS请求将包含一个重置连接标志,以指示它是重用的池连接。这导致SQL Server在内部调用sp_reset_connection进行清理工作,例如回滚未提交的事务,删除临时表,注销,登录等),如详细here所示。但是,sp_reset_connection由于数据库排序规则更改而无法将连接恢复为初始排序规则,从而导致登录失败。

下面是一些避免错误的技术。我建议选择3。

  1. 更改排序规则后调用静态SqlConnection.ClearAllPools()方法

  2. master命令指定TESTDB而不是ALTER DATABASE,以便重新使用现有的“主”池连接,而不是创建新的连接。由于池中不存在一个新连接,因此随后的PRINT命令将为TESTDB创建一个新连接。

  3. CREATE DATABASE语句中指定排序规则,并完全删除ALTER DATABASE命令

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...