Apa manfaat menggunakan "SET XACT_ABORT ON" dalam prosedur tersimpan?

Jawaban:

231

SET XACT_ABORT ONmemerintahkan SQL Server untuk mengembalikan seluruh transaksi dan membatalkan kumpulan ketika kesalahan run-time terjadi. Ini mencakup Anda dalam kasus-kasus seperti batas waktu perintah yang terjadi pada aplikasi klien daripada di dalam SQL Server itu sendiri (yang tidak tercakup oleh XACT_ABORT OFFpengaturan default .)

Karena batas waktu kueri akan membiarkan transaksi terbuka, SET XACT_ABORT ONdisarankan dalam semua prosedur tersimpan dengan transaksi eksplisit (kecuali jika Anda memiliki alasan khusus untuk melakukan hal lain) karena konsekuensi dari aplikasi yang melakukan pekerjaan pada koneksi dengan transaksi terbuka adalah bencana.

Ada gambaran yang sangat bagus di Blog Dan Guzman ,

Ben Griswold
sumber
41
jadi mengapa tidak AKTIF secara default?
Mike W
1
Apakah XACT_ABORT masih diperlukan jika Anda memiliki BEGIN TRY- BEGIN CATCHdan ROLLBACKdengan BEGIN CATCHblok di Sql?
user20358
1
@ user20358 BEGIN TRY- BEGIN CATCHtidak akan menangkap hal-hal seperti timeout yang terjadi pada aplikasi klien, dan beberapa kesalahan SQL juga tidak dapat ditandingi, membuat Anda dengan transaksi terbuka di mana Anda tidak akan mengharapkannya.
Tom Lint
37

Menurut pendapat saya SET XACT_ABORT ON dibuat usang dengan penambahan BEGIN TRY / BEGIN CATCH di SQL 2k5. Sebelum blok pengecualian dalam Transact-SQL sangat sulit untuk menangani kesalahan dan prosedur yang tidak seimbang terlalu umum (prosedur yang memiliki @@ TRANCOUNT berbeda saat keluar dibandingkan dengan entri).

Dengan penambahan penanganan pengecualian Transact-SQL jauh lebih mudah untuk menulis prosedur yang benar yang dijamin untuk menyeimbangkan transaksi dengan benar. Misalnya saya menggunakan templat ini untuk penanganan pengecualian dan transaksi bersarang :

create procedure [usp_my_procedure_name]
as
begin
    set nocount on;
    declare @trancount int;
    set @trancount = @@trancount;
    begin try
        if @trancount = 0
            begin transaction
        else
            save transaction usp_my_procedure_name;

        -- Do the actual work here

lbexit:
        if @trancount = 0   
            commit;
    end try
    begin catch
        declare @error int, @message varchar(4000), @xstate int;
        select @error = ERROR_NUMBER(), @message = ERROR_MESSAGE(), @xstate = XACT_STATE();
        if @xstate = -1
            rollback;
        if @xstate = 1 and @trancount = 0
            rollback
        if @xstate = 1 and @trancount > 0
            rollback transaction usp_my_procedure_name;

        raiserror ('usp_my_procedure_name: %d: %s', 16, 1, @error, @message) ;
    end catch   
end
go

Ini memungkinkan saya untuk menulis prosedur atom yang hanya mengembalikan pekerjaan mereka sendiri jika terjadi kesalahan yang dapat dipulihkan.

Salah satu masalah utama yang dihadapi prosedur Transact-SQL adalah kemurnian data : kadang-kadang parameter yang diterima atau data dalam tabel benar-benar salah, menghasilkan kesalahan kunci duplikat, kesalahan batasan referensial, periksa kesalahan batasan dan seterusnya dan seterusnya. Bagaimanapun, itulah peran dari kendala ini, jika kesalahan kemurnian data ini menjadi tidak mungkin dan semua tertangkap oleh logika bisnis, semua kendala akan menjadi usang (berlebihan berlebihan untuk efek). Jika XACT_ABORT HIDUP maka semua kesalahan ini mengakibatkan seluruh transaksi hilang, sebagai lawan mampu mengkodekan blok pengecualian yang menangani pengecualian dengan baik. Contoh khas sedang mencoba melakukan INSERT dan kembali ke UPDATE tentang pelanggaran PK.

Remus Rusanu
sumber
9
Kecuali untuk timeout klien ... dan pandangan saya adalah SET XACT_ABORT lebih efektif dalam SQL 2005 karena perilaku lebih dapat diprediksi: jauh lebih sedikit kesalahan batch dibatalkan.
gbn
7
Saya agak setuju, tetapi saya merencanakan kesalahan saya menangani semua kemungkinan, karena saya tahu saya akan disalahkan sebagai Pengembang DBA jika terjadi timeout perintah.
gbn
4
@RemusRusanu Bagaimana lagi Anda menangani operasi basis data yang sinkron dan berjalan lama?
Ian Boyd
5
Dokumentasi MSDN menyatakan: "XACT_ABORT harus diset ON untuk pernyataan modifikasi data dalam transaksi implisit atau eksplisit terhadap sebagian besar penyedia OLE DB, termasuk SQL Server. Satu-satunya kasus di mana opsi ini tidak diperlukan adalah jika penyedia mendukung transaksi bersarang." msdn.microsoft.com/en-us/library/ms188792(v=sql.120).aspx
Nathan
4
"Menurut pendapat saya SET XACT_ABORT ON dibuat usang dengan penambahan BEGIN TRY / BEGIN CATCH" - Saya mendengar Anda, tetapi silakan lihat sommarskog.se/error_handling/Part1.html
Insinyur Terbalik
22

Mengutip MSDN :

Ketika SET XACT_ABORT AKTIF, jika pernyataan Transact-SQL memunculkan kesalahan run-time, seluruh transaksi diakhiri dan dibatalkan. Ketika SET XACT_ABORT OFF, dalam beberapa kasus hanya pernyataan Transact-SQL yang meningkatkan kesalahan yang dibatalkan dan transaksi terus diproses.

Dalam praktiknya ini berarti bahwa beberapa pernyataan mungkin gagal, meninggalkan transaksi 'selesai sebagian', dan mungkin tidak ada tanda-tanda kegagalan ini untuk penelepon.

Contoh sederhana:

INSERT INTO t1 VALUES (1/0)    
INSERT INTO t2 VALUES (1/1)    
SELECT 'Everything is fine'

Kode ini akan mengeksekusi 'berhasil' dengan XACT_ABORT OFF, dan akan berakhir dengan kesalahan dengan XACT_ABORT ON ('INSERT INTO t2' tidak akan dieksekusi, dan aplikasi klien akan memunculkan pengecualian).

Sebagai pendekatan yang lebih fleksibel, Anda dapat memeriksa @@ ERROR setelah setiap pernyataan (old school), atau menggunakan TRY ... CATCH blocks (MSSQL2005 +). Secara pribadi saya lebih suka mengatur XACT_ABORT ON setiap kali tidak ada alasan untuk beberapa penanganan kesalahan lanjut.

VladV
sumber
8

Mengenai batas waktu klien dan penggunaan XACT_ABORT untuk mengatasinya, menurut saya setidaknya ada satu alasan yang sangat baik untuk memiliki batas waktu dalam API klien seperti SqlClient, dan itu adalah untuk menjaga kode aplikasi klien dari kebuntuan yang terjadi dalam kode server SQL. Dalam hal ini kode klien tidak memiliki kesalahan, tetapi harus melindunginya sendiri dari pemblokiran selamanya menunggu perintah untuk diselesaikan di server. Jadi sebaliknya, jika batas waktu klien harus ada untuk melindungi kode klien, demikian juga XACT_ABORT ON harus melindungi kode server dari pembatalan klien, jika kode server membutuhkan waktu lebih lama untuk dieksekusi daripada yang ingin ditunggu oleh klien.

ionutm
sumber
1

Ini digunakan dalam manajemen transaksi untuk memastikan bahwa setiap kesalahan mengakibatkan transaksi dibatalkan.

Dan Diplo
sumber