CREATE / ALTER / PRINT 후 System.Data.SqlClient.SqlException

Sep 03 2020

나는 다른 두 가지 질문에서 왔으며이 예외가 발생하는 이유를 이해하려고합니다.

Entity Framework seed-> SqlException : 연결을 재설정하면 초기 로그인과 다른 상태가됩니다. 로그인에 실패했습니다. 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"문을 실행하지 않아야합니까? 왜?

답변

2 DanGuzman Sep 06 2020 at 17:03

"연결을 재설정하면 초기 로그인과 다른 상태가됩니다. 로그인이 실패합니다."오류가 발생합니다. 데이터베이스 상태 변경 (데이터베이스 데이터 정렬 변경) 후 재사용 되는 풀링 된 연결 때문입니다. 다음은 내부적으로 발생하여 오류로 이어지는 것입니다.

이 코드가 실행될 때 :

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 설명 된대로 커밋되지 않은 트랜잭션 롤백, 임시 테이블 삭제, 로그 아웃, 로그인 등과 같은 정리 작업을 수행 하기 위해 내부적으로 호출 합니다 . 그러나 데이터베이스 데이터 정렬 변경으로 인해 연결을 초기 데이터 정렬로 되돌릴 수 없으므로 로그인 실패가 발생합니다.sp_reset_connection

다음은 오류를 방지하는 몇 가지 기술입니다. 옵션 3을 제안합니다.

  1. SqlConnection.ClearAllPools()데이터 정렬을 변경 한 후 정적 메서드를 호출합니다.

  2. 지정 master대신 TESTDB에 대한 ALTER DATABASE기존의 '마스터'풀링 된 연결이 새 연결을 만드는 대신 재사용되도록 명령. 다음 PRINT명령은 TESTDB풀에 존재하지 않기 때문에 새로운 연결을 생성 합니다.

  3. CREATE DATABASE명령문 에 데이터 정렬을 지정하고 ALTER DATABASE명령을 완전히 제거하십시오.