Trong bài viết này, chúng ta sẽ khám phá các Giao dịch lồng nhau của Máy chủ SQL, một khối giao dịch với một hoặc một số giao dịch.
Hình ảnh mô tả một mô hình đơn giản của giao dịch lồng nhau.
Giao dịch bên trong là một thủ tục được lưu trữ bao gồm các khối giao dịch. MSDN khuyến nghị “giữ các giao dịch càng ngắn càng tốt”, điều này hoàn toàn ngược lại với cách tiếp cận đầu tiên. Theo tôi, tôi không khuyến khích sử dụng các giao dịch lồng nhau. Tuy nhiên, đôi khi chúng tôi phải sử dụng chúng để giải quyết một số vấn đề kinh doanh.
Do đó, chúng ta sẽ tìm ra:
- Điều gì sẽ xảy ra khi một giao dịch bên ngoài được khôi phục hoặc được cam kết?
- Điều gì sẽ xảy ra khi một giao dịch nội bộ được hoàn nguyên hoặc được cam kết?
- Cách xử lý các lỗi giao dịch lồng nhau?
Để bắt đầu, chúng tôi sẽ tạo một bảng demo và thử nghiệm các trường hợp có thể xảy ra.
USE AdventureWorks -----Create Demo Table---- CREATE TABLE CodingSightDemo (NumberValue VARCHAR(20))
Trường hợp 1:Cả giao dịch bên ngoài và bên trong đều được cam kết.
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
Trong trường hợp này, tất cả các bản ghi được chèn thành công vào bảng. Chúng tôi đã giả định rằng mọi câu lệnh INSERT không trả về lỗi.
Trường hợp 2:Giao dịch bên ngoài được quay vòng trở lại , giao dịch nội bộ được cam kết .
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
Như bạn có thể thấy, các bản ghi không được chèn vào bảng vì giao dịch bên trong là một phần của giao dịch bên ngoài. Vì lý do này, giao dịch bên trong sẽ quay trở lại.
Trường hợp 3:Giao dịch bên ngoài được cam kết , giao dịch bên trong được quay vòng trở lại .
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
Trong trường hợp này, chúng tôi đã gặp lỗi và đã chèn câu lệnh mới nhất vào bảng. Do đó, một số câu hỏi nảy sinh:
- Tại sao chúng tôi gặp lỗi?
- Tại sao câu lệnh INSERT mới nhất được thêm vào bảng?
Theo quy tắc, câu lệnh ROLLBACK TRAN sẽ quay trở lại tất cả các giao dịch đang mở được thực hiện trong phiên hiện tại. Chúng tôi không thể viết một truy vấn vì nó sẽ trả về một lỗi.
BEGIN TRAN INSERT INTO CodingSightDemo VALUES('One') BEGIN TRAN INSERT INTO CodingSightDemo VALUES('Two') ROLLBACK TRAN ROLLBACK TRAN
Chúng tôi sẽ xem xét quy tắc này có thể ảnh hưởng như thế nào đến trường hợp của chúng tôi. Câu lệnh ROLLBACK TRAN quay trở lại các giao dịch bên trong và bên ngoài. Vì lý do này, chúng tôi gặp lỗi khi chạy câu lệnh COMMIT TRAN vì không có giao dịch nào đang mở.
Tiếp theo, chúng tôi sẽ thêm một câu lệnh xử lý lỗi vào truy vấn này và sửa đổi nó dựa trên cách tiếp cận lập trình phòng thủ (như Wikipedia nói:Lập trình phòng thủ là một dạng thiết kế phòng thủ nhằm đảm bảo chức năng liên tục của một phần mềm trong những trường hợp không lường trước được). Khi chúng tôi viết một truy vấn mà không quan tâm đến việc xử lý lỗi và gặp lỗi, chúng tôi có thể phải đối mặt với việc hỏng tính toàn vẹn của dữ liệu.
Với tập lệnh tiếp theo, chúng tôi sẽ sử dụng điểm lưu. Chúng đánh dấu một điểm trong giao dịch và nếu muốn, bạn có thể khôi phục tất cả các câu lệnh DML (Ngôn ngữ thao tác dữ liệu) về điểm đã đánh dấu.
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
Truy vấn này sẽ xử lý lỗi khi giao dịch bên trong bị lỗi. Ngoài ra, các giao dịch bên ngoài được cam kết thành công. Tuy nhiên, trong một số trường hợp, nếu giao dịch bên trong gặp lỗi, giao dịch bên ngoài phải khôi phục. Trong trường hợp này, chúng tôi sẽ sử dụng một biến cục bộ sẽ giữ và chuyển giá trị trạng thái lỗi truy vấn bên trong. Chúng tôi sẽ thiết kế truy vấn bên ngoài với giá trị biến này và truy vấn sẽ như sau.
--<*************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
Kết luận
Trong bài viết này, chúng tôi đã khám phá các giao dịch lồng nhau và phân tích cách xử lý lỗi trong loại truy vấn này. Quy tắc quan trọng nhất về loại giao dịch này là viết các truy vấn phòng thủ vì chúng ta có thể gặp lỗi trong các giao dịch bên ngoài hoặc bên trong. Vì lý do này, chúng tôi phải thiết kế hành vi xử lý lỗi của truy vấn.
Tài liệu tham khảo
Giao dịch lồng ghép
LƯU GIAO DỊCH