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