System.Data.SqlClient.SqlException 在 CREATE/ALTER/PRINT 之后
System.Data.SqlClient.SqlException after CREATE/ALTER/PRINT
我来自其他 2 个问题,我想了解为什么会出现此异常。
结果差异
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, Int32 timeout, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry)
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
...
如果我将第一个 Run(dbName...
更改为 Run("master"...
,它运行良好。
所以它与同一数据库上下文中的 运行 ALTER DATABASE
有关
“重置连接”是什么意思?
为什么会话“处于终止状态”。 ?
我应该避免在同一个数据库中使用 运行 "ALTER" 语句吗?为什么?
错误“重置连接导致与初始登录不同的状态。登录失败。”是由于 pooled connection 在数据库状态更改(数据库排序规则更改)后被重用。以下是导致错误的内部情况。
当这段代码 运行s:
Run(dbName, $"ALTER DATABASE [{dbName}] COLLATE Latin1_General_100_CI_AS");
ADO.NET 通过匹配连接字符串和安全上下文来查找现有的池连接。找到 None 是因为现有池连接(来自 CREATE DATABASE
查询)的连接字符串不同(master
数据库而不是 TESTDB
)。 ADO.NET 然后创建一个新连接,其中包括建立 TCP/IP 连接、身份验证和 SQL 服务器会话初始化。此新连接上的 ALTER DATABASE
查询是 运行。连接在处理时被添加到连接池中(超出 using
范围)。
然后这个 运行s:
Run(dbName, "PRINT 'HELLO'");
ADO.NET 找到现有的池 TESTDB
连接并使用它而不是实例化新连接。当 PRINT
命令发送到 SQL 服务器时,TDS 请求包含一个重置连接标志,以指示它是一个重用的池连接。这会导致 SQL 服务器在内部调用 sp_reset_connection
来执行清理工作,如回滚未提交的事务、删除临时表、注销、登录等),详见 here。但是,由于数据库排序规则更改,sp_reset_connection
无法将连接恢复为初始排序规则,导致登录失败。
下面是一些避免错误的技巧。我建议选项 3。
更改排序规则后调用静态SqlConnection.ClearAllPools()
方法
为 ALTER DATABASE
命令指定 master
而不是 TESTDB
以便重复使用现有的 'master' 池连接而不是创建新连接.随后的 PRINT
命令将为 TESTDB
创建一个新连接,因为池中不存在该连接。
在 CREATE DATABASE
语句中指定排序规则并完全删除 ALTER DATABASE
命令
我来自其他 2 个问题,我想了解为什么会出现此异常。
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, Int32 timeout, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry)
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
...
如果我将第一个 Run(dbName...
更改为 Run("master"...
,它运行良好。
所以它与同一数据库上下文中的 运行 ALTER DATABASE
有关
“重置连接”是什么意思? 为什么会话“处于终止状态”。 ? 我应该避免在同一个数据库中使用 运行 "ALTER" 语句吗?为什么?
错误“重置连接导致与初始登录不同的状态。登录失败。”是由于 pooled connection 在数据库状态更改(数据库排序规则更改)后被重用。以下是导致错误的内部情况。
当这段代码 运行s:
Run(dbName, $"ALTER DATABASE [{dbName}] COLLATE Latin1_General_100_CI_AS");
ADO.NET 通过匹配连接字符串和安全上下文来查找现有的池连接。找到 None 是因为现有池连接(来自 CREATE DATABASE
查询)的连接字符串不同(master
数据库而不是 TESTDB
)。 ADO.NET 然后创建一个新连接,其中包括建立 TCP/IP 连接、身份验证和 SQL 服务器会话初始化。此新连接上的 ALTER DATABASE
查询是 运行。连接在处理时被添加到连接池中(超出 using
范围)。
然后这个 运行s:
Run(dbName, "PRINT 'HELLO'");
ADO.NET 找到现有的池 TESTDB
连接并使用它而不是实例化新连接。当 PRINT
命令发送到 SQL 服务器时,TDS 请求包含一个重置连接标志,以指示它是一个重用的池连接。这会导致 SQL 服务器在内部调用 sp_reset_connection
来执行清理工作,如回滚未提交的事务、删除临时表、注销、登录等),详见 here。但是,由于数据库排序规则更改,sp_reset_connection
无法将连接恢复为初始排序规则,导致登录失败。
下面是一些避免错误的技巧。我建议选项 3。
更改排序规则后调用静态
SqlConnection.ClearAllPools()
方法为
ALTER DATABASE
命令指定master
而不是TESTDB
以便重复使用现有的 'master' 池连接而不是创建新连接.随后的PRINT
命令将为TESTDB
创建一个新连接,因为池中不存在该连接。在
CREATE DATABASE
语句中指定排序规则并完全删除ALTER DATABASE
命令