Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

Cara Menangani Kesalahan dalam Transaksi Bersarang SQL Server

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


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. SQL Server Ketersediaan tinggi:Tambahkan disk baru ke instance kluster failover yang ada

  2. Kembalikan Nomor Minggu ISO dari Tanggal di SQL Server (T-SQL)

  3. Apa yang dimaksud dengan kunci baris, halaman, dan tabel? Dan kapan mereka diakuisisi?

  4. Mengonfigurasi Grup Ketersediaan AlwaysOn - Bagian 2

  5. Menggunakan Penyimpanan Intel Optane untuk SQL Server