CREATE / ALTER / PRINT後のSystem.Data.SqlClient.SqlException
私は他の2つの質問から来ており、この例外が発生する理由を理解しようとしています。
EntityFrameworkシード-> SqlException:接続をリセットすると、最初のログインとは異なる状態になります。ログインに失敗します。結果-in-a-dif
「接続のリセット」とはどういう意味ですか?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」ステートメントを実行しないようにする必要がありますか?どうして?
回答
「接続をリセットすると、最初のログインとは異なる状態になります。ログインは失敗します。」というエラーが表示されます。これは、プールされた接続がデータベースの状態の変更(データベースの照合順序の変更)後に再利用されているためです。以下は、エラーにつながる内部で発生することです。
このコードが実行されるとき:
Run(dbName, $"ALTER DATABASE [{dbName}] COLLATE Latin1_General_100_CI_AS");
ADO.NETは、接続文字列とセキュリティコンテキストを照合することにより、既存のプールされた接続を探します。(CREATE DATABASEクエリからの)既存のプールされた接続の接続文字列が異なるため(のmaster代わりにデータベース)、何も見つかりませんTESTDB。次に、ADO.NETは、TCP / IP接続の確立、認証、およびSQLServerセッションの初期化を含む新しい接続を作成します。ALTER DATABASEクエリは、この新しい接続上で実行されます。接続は、破棄されると接続プールに追加されます(usingスコープ外になります)。
次に、これが実行されます。
Run(dbName, "PRINT 'HELLO'");
ADO.NETは、既存のプールされたTESTDB接続を見つけて、新しい接続をインスタンス化する代わりにそれを使用します。ときにPRINTコマンドをSQL Serverに送信され、TDSの要求は、それが再利用プールされた接続だ示すためにリセット接続フラグが含まれています。これにより、SQL Serverは内部的に呼び出しsp_reset_connectionて、コミットされていないトランザクションのロールバック、一時テーブルの削除、ログアウト、ログインなどのクリーンアップ作業を実行します。ただし、sp_reset_connectionデータベースの照合順序が変更されたため、接続を最初の照合順序に戻すことができず、ログインに失敗します。
以下は、エラーを回避するためのいくつかのテクニックです。オプション3をお勧めします。
SqlConnection.ClearAllPools()照合順序を変更した後、静的メソッドを呼び出しますコマンドの
master代わりにTESTDBを指定ALTER DATABASEして、新しい接続を作成する代わりに既存の「マスター」プール接続を再利用します。その後のPRINTコマンドはTESTDB、プールに接続が存在しないため、の新しい接続を作成します。CREATE DATABASEステートメントで照合を指定し、ALTER DATABASEコマンドを完全に削除します