Pada artikel ini, kita akan menjelajahi SQL Server Nested Transactions, sebuah blok transaksi dengan satu atau beberapa transaksi.
Gambar tersebut menjelaskan model sederhana dari transaksi bertingkat.
Transaksi dalam adalah prosedur tersimpan yang terdiri dari blok transaksi. MSDN merekomendasikan "menjaga transaksi sesingkat mungkin" yang benar-benar berlawanan dengan pendekatan pertama. Menurut pendapat saya, saya tidak menyarankan menggunakan transaksi bersarang. Namun, terkadang kita harus menggunakannya untuk menyelesaikan beberapa masalah bisnis.
Jadi, kita akan mencari tahu:
- Apa yang akan terjadi ketika transaksi luar dibatalkan atau dilakukan?
- Apa yang akan terjadi ketika transaksi internal dibatalkan atau dilakukan?
- Bagaimana cara menangani kesalahan transaksi bersarang?
Untuk memulainya, kami akan membuat tabel demo dan menguji kemungkinan kasus.
USE AdventureWorks -----Create Demo Table---- CREATE TABLE CodingSightDemo (NumberValue VARCHAR(20))
Kasus 1:Transaksi luar dan dalam dilakukan.
TRUNCATE TABLE CodingSightDemo --<*************OUTHER TRANSACTION START*************> BEGIN TRAN INSERT INTO CodingSightDemo VALUES('One') --<INNER TRANSACTION START> BEGIN TRAN INSERT INTO CodingSightDemo VALUES('Two') COMMIT TRAN --< INNER TRANSACTION END> INSERT INTO CodingSightDemo VALUES('Three') COMMIT TRAN --<************* OUTHER TRANSACTION END*************> SELECT * FROM CodingSightDemo
Dalam hal ini, semua catatan berhasil dimasukkan ke dalam tabel. Kami berasumsi bahwa setiap pernyataan INSERT tidak mengembalikan kesalahan.
Kasus 2:Transaksi luar dibatalkan , transaksi batin dikomit .
TRUNCATE TABLE CodingSightDemo --<*************OUTHER TRANSACTION START*************> BEGIN TRAN INSERT INTO CodingSightDemo VALUES('One') --<INNER TRANSACTION START> BEGIN TRAN INSERT INTO CodingSightDemo VALUES('Two') COMMIT TRAN --< INNER TRANSACTION END> INSERT INTO CodingSightDemo VALUES('Three') rollback TRAN --<************* OUTHER TRANSACTION END*************> SELECT * FROM CodingSightDemo
Seperti yang Anda lihat, catatan tidak dimasukkan ke dalam tabel karena transaksi dalam adalah bagian dari transaksi luar. Karena alasan ini, transaksi internal dibatalkan.
Kasus 3:Transaksi luar dilakukan , transaksi dalam dibatalkan .
TRUNCATE TABLE CodingSightDemo --<*************OUTHER TRANSACTION START*************> BEGIN TRAN INSERT INTO CodingSightDemo VALUES('One') --<INNER TRANSACTION START> BEGIN TRAN INSERT INTO CodingSightDemo VALUES('Two') ROLLBACK TRAN --< INNER TRANSACTION END> INSERT INTO CodingSightDemo VALUES('Three') COMMIT TRAN --<************* OUTHER TRANSACTION END*************> SELECT * FROM CodingSightDemo
Dalam hal ini, kami mendapat kesalahan dan memasukkan pernyataan terbaru ke dalam tabel. Akibatnya, beberapa pertanyaan muncul:
- Mengapa kami mendapatkan kesalahan?
- Mengapa pernyataan INSERT terbaru ditambahkan ke tabel?
Sebagai aturan, pernyataan ROLLBACK TRAN mengembalikan semua transaksi terbuka yang dieksekusi di sesi saat ini. Kami tidak dapat menulis kueri karena akan mengembalikan kesalahan.
BEGIN TRAN INSERT INTO CodingSightDemo VALUES('One') BEGIN TRAN INSERT INTO CodingSightDemo VALUES('Two') ROLLBACK TRAN ROLLBACK TRAN
Kami akan memeriksa bagaimana aturan ini dapat berdampak pada kasus kami. Pernyataan ROLLBACK TRAN mengembalikan transaksi dalam dan luar. Untuk alasan ini, kami mendapatkan kesalahan saat menjalankan pernyataan COMMIT TRAN karena tidak ada transaksi yang terbuka.
Selanjutnya, kami akan menambahkan pernyataan penanganan kesalahan ke kueri ini dan memodifikasinya berdasarkan pendekatan pemrograman defensif (seperti yang dinyatakan Wikipedia:Pemrograman defensif adalah bentuk desain defensif yang dimaksudkan untuk memastikan fungsi berkelanjutan dari perangkat lunak dalam keadaan yang tidak terduga). Saat kami menulis kueri tanpa memperhatikan penanganan kesalahan dan mendapatkan kesalahan, kami mungkin menghadapi kerusakan integritas data.
Dengan script selanjutnya, kita akan menggunakan save point. Mereka menandai titik dalam transaksi dan jika Anda mau, Anda dapat mengembalikan semua pernyataan DML (Bahasa Manipulasi Data) ke titik yang ditandai.
BEGIN TRY BEGIN TRAN INSERT INTO CodingSightDemo VALUES('One') --<INNER TRANSACTION START> SAVE TRANSACTION innerTRAN BEGIN TRY BEGIN TRAN INSERT INTO CodingSightDemo VALUES('Two') COMMIT TRAN END TRY BEGIN CATCH IF XACT_STATE() <> 0 BEGIN ROLLBACK TRANSACTION innerTRAN PRINT 'Roll back occurs for inner tran' END IF XACT_STATE() <> 0 BEGIN COMMIT TRAN PRINT 'Commit occurs for firt open tran' END END CATCH --< INNER TRANSACTION END> INSERT INTO CodingSightDemo VALUES('Three') COMMIT TRAN END TRY BEGIN CATCH BEGIN IF XACT_STATE() <> 0 ROLLBACK TRAN PRINT 'Roll back occurs for outer tran' END END CATCH --<************* OUTHER TRANSACTION END*************> SELECT * FROM CodingSightDemo
Kueri ini akan menangani kesalahan ketika transaksi dalam mendapatkan kesalahan. Juga, transaksi luar berhasil dilakukan. Namun, dalam beberapa kasus, jika transaksi dalam mengalami kesalahan, transaksi luar harus melakukan roll back. Dalam hal ini, kami akan menggunakan variabel lokal yang akan menyimpan dan meneruskan nilai status kesalahan kueri dalam. Kami akan mendesain kueri luar dengan nilai variabel ini dan kuerinya akan menjadi sebagai berikut.
--<*************OUTHER TRANSACTION START*************> DECLARE @innertranerror as int=0 BEGIN TRY BEGIN TRAN INSERT INTO CodingSightDemo VALUES('One') --<INNER TRANSACTION START> SAVE TRANSACTION innerTRAN BEGIN TRY BEGIN TRAN INSERT INTO CodingSightDemo VALUES('Two') COMMIT TRAN END TRY BEGIN CATCH IF XACT_STATE() <> 0 BEGIN SET @innertranerror=1 ROLLBACK TRANSACTION innerTRAN PRINT 'Roll back occurs for inner tran' END IF XACT_STATE() <> 0 BEGIN COMMIT TRAN PRINT 'Commit occurs for firt open tran' END END CATCH --< INNER TRANSACTION END> INSERT INTO CodingSightDemo VALUES('Three') if @innertranerror=0 BEGIN COMMIT TRAN END IF @innertranerror=1 BEGIN ROLLBACK TRAN END END TRY BEGIN CATCH BEGIN IF XACT_STATE() <> 0 ROLLBACK TRAN PRINT 'Roll back occurs for outer tran' END END CATCH --<************* OUTHER TRANSACTION END*************> SELECT * FROM CodingSightDemo
Kesimpulan
Dalam artikel ini, kami menjelajahi transaksi bersarang dan menganalisis cara menangani kesalahan dalam jenis kueri ini. Aturan terpenting tentang jenis transaksi ini adalah menulis kueri defensif karena kita bisa mendapatkan kesalahan dalam transaksi luar atau dalam. Untuk alasan ini, kita harus merancang perilaku penanganan kesalahan kueri.
Referensi
Transaksi Bersarang
SIMPAN TRANSAKSI