Saya memiliki prosedur tersimpan yang hanya menjalankan 3 prosedur tersimpan di dalamnya. Saya hanya menggunakan 1 parameter untuk menyimpan jika master SP berhasil.
Jika prosedur tersimpan pertama berfungsi dengan baik dalam prosedur tersimpan master, tetapi prosedur tersimpan 2 gagal, maka akankah secara otomatis memutar kembali semua SP di master SP atau apakah saya harus membuat perintah?
Inilah prosedur saya:
CREATE PROCEDURE [dbo].[spSavesomename]
-- Add the parameters for the stored procedure here
@successful bit = null output
AS
BEGIN
begin transaction createSavebillinginvoice
begin Try
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
BEGIN
EXEC [dbo].[spNewBilling1]
END
BEGIN
EXEC [dbo].[spNewBilling2]
END
BEGIN
EXEC [dbo].[spNewBilling3]
END
set @successful = 1
end Try
begin Catch
rollback transaction createSavesomename
insert into dbo.tblErrorMessage(spName, errorMessage, systemDate)
values ('spSavesomename', ERROR_MESSAGE(), getdate())
return
end Catch
commit transaction createSavesomename
return
END
GO
sql-server
stored-procedures
transaction
pengguna2483342
sumber
sumber
spNewBilling3
melempar kesalahan, tetapi Anda tidak ingin memutar kembalispNewBilling2
atauspNewBilling1
, kemudian hanya menghapus[begin|rollback|commit] transaction createSavebillinginvoice
darispSavesomename
.Jawaban:
Hanya diberi kode yang ditunjukkan dalam pertanyaan, dan dengan asumsi bahwa tidak satu pun dari ketiga sub-procs memiliki penanganan transaksi eksplisit, maka ya, kesalahan dalam salah satu dari tiga sub-procs akan ditangkap dan
ROLLBACK
diCATCH
blok akan memutar kembali semua pekerjaan.TAPI di sini ada beberapa hal yang perlu diperhatikan tentang transaksi (setidaknya dalam SQL Server):
Hanya ada satu transaksi nyata (yang pertama), tidak peduli berapa kali Anda menelepon
BEGIN TRAN
BEGIN TRAN
, apakah namanya disebutkan, penghitung transaksi bertambah 1.SELECT @@TRANCOUNT;
COMMIT
perintah dikeluarkan saat@@TRANCOUNT
berada di 2 atau di atas melakukan apa-apa lebih dari mengurangi, satu per satu, counter transaksi.COMMIT
dikeluarkan ketika@@TRANCOUNT
itu di1
Simpan poin memungkinkan untuk menciptakan subset dari pekerjaan dalam satu transaksi yang dapat dibatalkan.
SAVE TRAN {save_point_name}
perintahROLLBACK {save_point_name}
. (lebih lanjut tentang ini di bawah)SAVE TRAN {save_point_name}
, termasuk setiap titik penyimpanan yang dibuat setelah yang digulirkan kembali telah dibuat (karenanya "bersarang").SAVE TRAN
tidak dapat dibatalkan kecuali dengan mengeluarkanROLLBACK
seluruh transaksi.COMMIT
saat@@TRANCOUNT
berada di 2 atau di atas, tidak berpengaruh pada poin simpanan (karena sekali lagi, tingkat transaksi di atas 1 tidak ada di luar penghitung itu).Anda tidak dapat melakukan transaksi bernama tertentu. "Nama" transaksi, jika disediakan bersama dengan
COMMIT
, diabaikan dan hanya ada untuk dibaca.Yang
ROLLBACK
dikeluarkan tanpa nama akan selalu mengembalikan SEMUA transaksi.Yang
ROLLBACK
diterbitkan dengan nama harus sesuai dengan:Asumsikan tidak
SAVE TRAN
telah dipanggil dengan nama transaksi yang sama, ini akan mengembalikan semua transaksi.Perilaku ini akan "membatalkan" semua perubahan yang dibuat sejak yang terakhir
SAVE TRAN {save_point_name}
dipanggil.SAVE TRAN
perintah yang dikeluarkan dengan namanya, maka setiap ROLLBACK dari nama transaksi tersebut akan membatalkan setiap titik penyimpanan hingga tidak ada lagi yang tersisa dari nama itu. Setelah itu, ROLLBACK yang diterbitkan dengan nama itu akan mengembalikan semua transaksi.Misalnya, asumsikan perintah berikut dijalankan dalam urutan yang ditunjukkan:
Sekarang, jika Anda mengeluarkan (masing-masing skenario berikut ini tidak tergantung satu sama lain):
ROLLBACK TRAN B
sekali: Ini akan membatalkan "DML Permintaan 4".@@TRANCOUNT
masih 2.ROLLBACK TRAN B
dua kali: Ini akan membatalkan "DML Query 4" dan kemudian kesalahan karena tidak ada titik penyimpanan yang sesuai untuk "B".@@TRANCOUNT
masih 2.ROLLBACK TRAN A
sekali: Ini akan membatalkan "DML Kueri 4" dan "DML Kueri 3".@@TRANCOUNT
masih 2.ROLLBACK TRAN A
dua kali: Ini akan membatalkan "DML Kueri 4", "DML Kueri 3", dan "DML Kueri 2".@@TRANCOUNT
masih 2.ROLLBACK TRAN A
tiga kali: Ini akan membatalkan "DML Query 4", "DML Query 3", dan "DML Query 2". Kemudian akan mengembalikan seluruh transaksi (yang tersisa hanyalah "DML Kueri 1").@@TRANCOUNT
sekarang 0.COMMIT
sekali:@@TRANCOUNT
turun ke 1.COMMIT
sekali dan kemudianROLLBACK TRAN B
sekali:@@TRANCOUNT
turun ke 1. Lalu itu akan membatalkan "DML Permintaan 4" (membuktikan bahwa COMMIT tidak melakukan apa-apa).@@TRANCOUNT
masih 1.Nama transaksi dan simpan nama titik:
Prosedur tersimpan bukan merupakan transaksi implisit. Setiap permintaan jika tidak ada transaksi eksplisit yang telah dimulai, merupakan transaksi implisit. Inilah sebabnya mengapa transaksi eksplisit di sekitar kueri tunggal tidak diperlukan kecuali jika ada alasan terprogram untuk melakukan
ROLLBACK
, jika tidak, setiap kesalahan dalam kueri adalah kemunduran otomatis kueri itu.Saat memanggil prosedur tersimpan, harus keluar dengan nilai
@@TRANCOUNT
yang sama seperti ketika dipanggil. Artinya, Anda tidak dapat:BEGIN TRAN
di dalam proc tanpa melakukan itu, berharap untuk melakukan dalam proses panggilan / orang tua.ROLLBACK
jika transaksi eksplisit dimulai sebelum proc dipanggil karena akan kembali@@TRANCOUNT
ke 0.Jika Anda keluar dari prosedur tersimpan dengan jumlah transaksi yang lebih tinggi atau lebih rendah daripada ketika itu menatap, Anda akan mendapatkan kesalahan yang mirip dengan:
Variabel tabel, seperti halnya variabel biasa, tidak terikat oleh transaksi.
Mengenai memiliki penanganan transaksi dalam procs yang dapat disebut secara independen (dan karenanya memerlukan penanganan transaksi) atau panggilan dari procs lain (karenanya tidak memerlukan penanganan transaksi): ini dapat dilakukan dalam beberapa cara yang berbeda.
Cara saya telah menanganinya selama beberapa tahun sekarang yang tampaknya bekerja dengan baik adalah dengan hanya
BEGIN
/COMMIT
/ROLLBACK
pada lapisan paling luar. Panggilan sub-proc cukup lewati saja perintah transaksi. Saya telah menguraikan di bawah ini apa yang saya masukkan ke dalam setiap proc (well, masing-masing membutuhkan penanganan transaksi).DECLARE @InNestedTransaction BIT;
Di tempat yang sederhana
BEGIN TRAN
, lakukan:Di tempat yang sederhana
COMMIT
, lakukan:Di tempat yang sederhana
ROLLBACK
, lakukan:Metode ini harus bekerja sama terlepas dari apakah transaksi dimulai dalam SQL Server atau jika dimulai pada lapisan aplikasi.
Untuk templat lengkap penanganan Transaksi ini dalam
TRY...CATCH
konstruk, silakan lihat jawaban saya untuk pertanyaan DBA.SE berikut: Apakah kami diharuskan menangani Transaksi dalam Kode C # dan juga dalam prosedur tersimpan .Bergerak melampaui "dasar-dasar", ada beberapa nuansa transaksi tambahan yang harus diperhatikan:
Secara default, sebagian besar waktu Transaksi tidak dibatalkan / dibatalkan secara otomatis saat terjadi kesalahan. Ini biasanya bukan masalah selama Anda memiliki penanganan kesalahan yang tepat dan menelepon
ROLLBACK
diri sendiri. Namun, kadang-kadang hal menjadi rumit, seperti dalam kasus kesalahan batch-dibatalkan, atau ketika menggunakanOPENQUERY
(atau Server Terkait pada umumnya) dan kesalahan terjadi pada sistem jarak jauh. Sementara sebagian besar kesalahan dapat terjebak menggunakanTRY...CATCH
, ada dua yang tidak bisa dijebak seperti itu (tidak bisa mengingat yang mana pada saat ini - meneliti). Dalam kasus ini, Anda harus menggunakanSET XACT_ABORT ON
untuk mengembalikan transaksi dengan benar.SET XACT_ABORT ON menyebabkan SQL Server segera memutar kembali segala Transaksi (jika ada yang aktif) dan membatalkan kumpulan jika ada kesalahan. Pengaturan ini ada sebelum SQL Server 2005, yang memperkenalkan
TRY...CATCH
konstruk. Sebagian besar,TRY...CATCH
menangani sebagian besar situasi dan sebagian besar kebutuhan usangXACT_ABORT ON
. Namun, ketika menggunakanOPENQUERY
(dan mungkin satu skenario lain yang saya tidak ingat saat ini), maka Anda masih harus menggunakanSET XACT_ABORT ON;
.Di dalam Pemicu,
XACT_ABORT
secara implisit diatur keON
. Hal ini menyebabkan setiap kesalahan dalam Pemicu untuk membatalkan seluruh pernyataan DML yang menembakkan Pemicu.Anda harus selalu memiliki penanganan kesalahan yang tepat, terutama saat menggunakan Transaksi. The
TRY...CATCH
membangun, diperkenalkan pada SQL Server 2005, menyediakan sarana penanganan hampir semua situasi, menyambut perbaikan atas pengujian untuk@@ERROR
setelah setiap pernyataan, yang tidak membantu banyak dengan kesalahan batch-batal.TRY...CATCH
memperkenalkan "negara" baru, namun. Ketika tidak menggunakanTRY...CATCH
konstruk, jika Anda memiliki Transaksi aktif dan terjadi kesalahan, maka ada beberapa jalur yang dapat diambil:XACT_ABORT OFF
dan kesalahan pembatalan pernyataan: Transaksi masih aktif dan pemrosesan dilanjutkan dengan pernyataan berikutnya , jika ada.XACT_ABORT OFF
dan sebagian besar kesalahan pembatalan bets: Transaksi masih aktif dan pemrosesan berlanjut dengan bets berikutnya , jika ada.XACT_ABORT OFF
dan kesalahan pembatalan bets tertentu: Transaksi dibatalkan dan pemrosesan dilanjutkan dengan bets berikutnya , jika ada.XACT_ABORT ON
dan kesalahan apa pun : Transaksi dibatalkan dan pemrosesan dilanjutkan dengan batch berikutnya , jika ada.NAMUN, saat menggunakan
TRY...CATCH
, kesalahan yang dibatalkan batch tidak membatalkan batch, tetapi alih-alih mentransfer kontrol keCATCH
blok. KetikaXACT_ABORT
adalahOFF
, Transaksi akan tetap aktif sebagian besar waktu, dan Anda akan perluCOMMIT
, atau paling mungkin,ROLLBACK
. Tapi ketika menghadapi kesalahan batch-batal tertentu (seperti denganOPENQUERY
), atau ketikaXACT_ABORT
adalahON
, Transaksi akan berada dalam keadaan baru, "uncommitable". Dalam keadaan ini Anda tidak bisaCOMMIT
, Anda juga tidak bisa melakukan operasi DML. Semua dapat Anda lakukan adalahROLLBACK
danSELECT
pernyataan. Akan tetapi, dalam keadaan "tidak dapat diterima" ini, Transaksi dibatalkan karena kesalahan yang terjadi, dan mengeluarkannyaROLLBACK
hanyalah formalitas, tetapi harus dilakukan.Fungsi, XACT_STATE , dapat digunakan untuk menentukan apakah suatu Transaksi aktif, tidak dikomunikasikan, atau tidak ada. Dianjurkan (oleh beberapa orang, setidaknya) untuk memeriksa fungsi ini di
CATCH
blok untuk menentukan apakah hasilnya-1
(yaitu uncommitable) alih-alih menguji jika@@TRANCOUNT > 0
. Tetapi denganXACT_ABORT ON
, itu harus menjadi satu-satunya keadaan yang memungkinkan untuk dilakukan, sehingga tampaknya pengujian untuk@@TRANCOUNT > 0
danXACT_STATE() <> 0
setara. Di sisi lain, ketikaXACT_ABORT
adalahOFF
dan ada transaksi aktif, maka ada kemungkinan untuk memiliki keadaan baik1
atau-1
diCATCH
blok, yang memungkinkan untuk kemungkinan menerbitkanCOMMIT
bukanROLLBACK
(meskipun, saya tidak bisa memikirkan kasus ketika seseorang inginCOMMIT
jika Transaksi berkomitmen). Informasi dan penelitian lebih lanjut tentang penggunaanXACT_STATE()
dalamCATCH
blokXACT_ABORT ON
dapat ditemukan dalam jawaban saya untuk pertanyaan DBA.SE berikut: Dalam kasus apa transaksi dapat dilakukan dari dalam blok CATCH ketika XACT_ABORT disetel ke ON? . Harap perhatikan bahwa ada bug minorXACT_STATE()
yang menyebabkannya salah1
dalam skenario tertentu: XACT_STATE () mengembalikan 1 ketika digunakan dalam SELECT dengan beberapa variabel sistem tetapi tanpa klausa FROM dari klausaCatatan tentang kode asli:
BEGIN
danEND
sekitar setiapEXEC
panggilansumber
Compile errors, such as syntax errors, that prevent a batch from running
danErrors that occur during statement-level recompilation, such as object name resolution errors that occur after compilation because of deferred name resolution.
. Tetapi mereka tidak sering terjadi, dan ketika Anda menemukan situasi seperti itu, perbaikilah (jika itu bug dalam kode) atau letakkan di sub-proses (EXEC
atausp_executesql
) sehinggaTRY...CATCH
dapat menjebaknya.Ya, jika karena kesalahan kode rollback dalam pernyataan tangkap prosedur tersimpan master Anda akan dieksekusi, itu akan mengembalikan semua operasi yang dilakukan oleh pernyataan langsung atau melalui salah satu prosedur tersimpan yang tersimpan di dalamnya.
Bahkan jika Anda belum menerapkan transaksi eksplisit dalam prosedur tersimpan bersarang Anda, prosedur tersimpan ini akan menggunakan transaksi implisit dan akan melakukan penyelesaian TETAPI baik Anda telah melakukan transaksi eksplisit atau implisit dalam prosedur tersimpan tersimpan yang tersimpan. Mesin SQL Server akan mengabaikannya dan akan kembalikan semua tindakan dengan prosedur tersimpan bersarang ini jika prosedur tersimpan master gagal dan transaksi didukung oleh roll.
Setiap kali transaksi dilakukan atau dibatalkan berdasarkan tindakan yang dilakukan pada akhir transaksi terluar. Jika transaksi luar dilakukan, transaksi bersarang dalam juga dilakukan. Jika transaksi luar dibatalkan, maka semua transaksi dalam juga dibatalkan, terlepas dari apakah transaksi dalam itu dilakukan secara individual atau tidak.
Untuk referensi http://technet.microsoft.com/en-us/library/ms189336(v=sql.105).aspx
sumber