CREATE / ALTER / PRINT sonrasında System.Data.SqlClient.SqlException

Sep 03 2020

Diğer 2 sorudan geliyorum ve bu istisnanın neden olduğunu anlamaya çalışıyorum.

Entity Framework seed -> SqlException: Bağlantının sıfırlanması, ilk oturum açmadan farklı bir duruma neden olur. Giriş başarısız olur. sonuç-in-a-dif

"Bağlantıyı sıfırlamak" ne anlama geliyor? System.Data.SqlClient.SqlException (0x80131904)

Bu kod istisnayı yeniden üretir.

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();
}

Tam yığın izleme

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()
...

Ben ilk değiştirirseniz Run(dbName...için Run("master"...bu cezayı çalışır. Yani ALTER DATABASEaynı veritabanı bağlamında çalıştırmakla ilgili

"Bağlantıyı sıfırlamak" ne anlama geliyor? Oturum neden "öldürme durumunda"? ? Aynı veritabanı içinde "ALTER" ifadelerini çalıştırmaktan kaçınmalı mıyım? Neden?

Yanıtlar

2 DanGuzman Sep 06 2020 at 17:03

"Bağlantının sıfırlanması, ilk oturum açma işleminden farklı bir duruma neden olur. Oturum açma başarısız olur." havuza alınmış bir bağlantının veritabanı durumu değişikliğinden (veritabanı harmanlama değişikliği) sonra yeniden kullanılmasından kaynaklanmaktadır . Aşağıda, hataya neden olan dahili olarak neler olduğu anlatılmaktadır.

Bu kod çalıştırıldığında:

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

ADO.NET, bağlantı dizesini ve güvenlik bağlamını eşleştirerek var olan havuzlanmış bir bağlantıyı arar. Yok, var olan havuzlanmış bağlantının ( CREATE DATABASEsorgudan) bağlantı dizesi farklı olduğundan ( masterbunun yerine veritabanı TESTDB) bulunur. ADO.NET daha sonra bir TCP / IP bağlantısı, kimlik doğrulama ve SQL Server oturumu başlatmayı içeren yeni bir bağlantı oluşturur. ALTER DATABASESorgu bu yeni bağlantıda çalıştırılır. Bağlantı, elden çıkarıldığında bağlantı havuzuna eklenir ( usingkapsamın dışına çıkar ).

Sonra bu çalışır:

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

ADO.NET var olan havuzlanmış TESTDBbağlantıyı bulur ve yeni bir bağlantı oluşturmak yerine bunu kullanır. Ne zaman PRINTkomut SQL Server gönderilir, TDS isteği bir yeniden toplanmış bağlantısıdır belirtmek için bir sıfırlama bağlantı bayrağını içerir. Bu, SQL Server'ın sp_reset_connection, burada ayrıntılı olarak açıklandığı gibi geri alınmayan işlemleri geri alma, geçici tabloları bırakma, oturumu kapatma, oturum açma vb. Gibi temizleme işlerini yapmak için dahili olarak çağırmasına neden olur . Ancak, sp_reset_connectionveritabanı harmanlama değişikliği nedeniyle bağlantı ilk harmanlamaya geri döndürülemiyor ve bu da oturum açma hatasına neden oluyor.

Hatayı önlemek için bazı teknikler aşağıdadır. 3. seçeneği öneririm.

  1. SqlConnection.ClearAllPools()harmanlamayı değiştirdikten sonra statik yöntemi çağırın

  2. Mevcut 'ana' havuzlanmış bağlantının yeni bir bağlantı oluşturmak yerine yeniden kullanılması için komut masteryerine belirtiniz . Sonraki komut , havuzda mevcut olmadığı için yeni bir bağlantı oluşturacaktır .TESTDBALTER DATABASEPRINTTESTDB

  3. CREATE DATABASEifadede harmanlamayı belirtin ve ALTER DATABASEkomutu tamamen kaldırın