Dari aplikasi .NET 3.5 / C #, saya ingin menangkapnya SqlException
tetapi hanya jika hal itu disebabkan oleh kebuntuan pada contoh SQL Server 2008.
Pesan kesalahan tipikal adalah Transaction (Process ID 58) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
Namun, tampaknya itu bukan kode kesalahan yang terdokumentasi untuk pengecualian ini.
Memfilter pengecualian terhadap keberadaan kata kunci kebuntuan dalam pesan mereka tampaknya merupakan cara yang sangat buruk untuk mencapai perilaku ini. Apakah seseorang tahu cara yang benar untuk melakukan ini?
.net
sql-server-2008
deadlock
try-catch
sqlexception
Joannes Vermorel
sumber
sumber
select * from master.dbo.sysmessages where error=1205
Jawaban:
Kode kesalahan khusus Microsft SQL Server untuk kebuntuan adalah 1205 jadi Anda harus menangani SqlException dan memeriksanya. Jadi, misalnya jika untuk semua jenis SqlException Anda ingin gelembung pengecualiannya:
Atau, menggunakan pemfilteran pengecualian yang tersedia di C # 6
Hal praktis yang harus dilakukan untuk menemukan kode kesalahan SQL yang sebenarnya untuk pesan tertentu, adalah dengan mencari di sys.messages di SQL Server.
misalnya
SELECT * FROM sys.messages WHERE text LIKE '%deadlock%' AND language_id=1033
Cara alternatif untuk menangani kebuntuan (dari SQL Server 2005 dan yang lebih baru), adalah melakukannya dalam prosedur yang tersimpan menggunakan dukungan COBA ... CATCH:
BEGIN TRY -- some sql statements END TRY BEGIN CATCH IF (ERROR_NUMBER() = 1205) -- is a deadlock ELSE -- is not a deadlock END CATCH
Ada contoh lengkap di sini di MSDN tentang bagaimana menerapkan logika coba lagi kebuntuan murni dalam SQL.
sumber
SqlException
mungkin digabungkan satu sama lain. Jadi kita mungkin perlu menangkap jenis pengecualian apa pun dan memeriksanya, jika mereka bukan pengecualian kebuntuan secara langsung, periksa secara rekursifInnerException
.Karena saya kira Anda mungkin ingin mendeteksi kebuntuan, untuk dapat mencoba kembali operasi yang gagal, saya ingin memperingatkan Anda untuk sedikit gotcha. Saya harap Anda memaafkan saya karena sedikit keluar dari topik di sini.
Kebuntuan yang terdeteksi oleh basis data akan secara efektif mengembalikan transaksi yang Anda jalankan (jika ada), sementara koneksi tetap terbuka di .NET. Mencoba kembali operasi tersebut (dalam koneksi yang sama), berarti akan dijalankan dalam konteks tanpa transaksi dan ini dapat menyebabkan kerusakan data.
Penting untuk menyadari hal ini. Sebaiknya pertimbangkan koneksi lengkap ditakdirkan jika terjadi kegagalan yang disebabkan oleh SQL. Mencoba kembali operasi hanya dapat dilakukan pada level di mana transaksi ditentukan (dengan membuat ulang transaksi itu dan koneksinya).
Jadi ketika Anda mencoba kembali operasi yang gagal, pastikan Anda membuka koneksi yang benar-benar baru dan memulai transaksi baru.
sumber
Berikut adalah cara C # 6 untuk mendeteksi kebuntuan.
try { //todo: Execute SQL. //IMPORTANT, if you used Connection.BeginTransaction(), this try..catch must surround that code. You must rollback the original transaction, then recreate it and re-run all the code. } catch (SqlException ex) when (ex.Number == 1205) { //todo: Retry SQL }
Pastikan try..catch ini mengelilingi seluruh transaksi Anda. Menurut @Steven (lihat jawabannya untuk detailnya), ketika perintah sql gagal karena kebuntuan, itu menyebabkan transaksi digulung kembali dan, jika Anda tidak membuat ulang transaksi, percobaan ulang Anda akan dieksekusi di luar konteks transaksi dan dapat mengakibatkan inkonsistensi data.
sumber