Nếu bạn nhận được lỗi Msg 3902, Cấp độ 16, có nội dung “Yêu cầu GIAO DỊCH CAM KẾT không có GIAO DỊCH BẮT ĐẦU tương ứng”, có thể là do bạn gặp phải COMMIT
tuyên bố.
Bạn có thể nhận được điều này do triển khai xử lý lỗi và quên rằng bạn đã cam kết hoặc khôi phục giao dịch ở nơi khác trong mã của bạn.
Ví dụ về Lỗi
Dưới đây là một ví dụ đơn giản để giải thích lỗi:
SELECT ProductName, ProductPrice FROM Products;
COMMIT TRANSACTION;
Kết quả:
(7 rows affected) Msg 3902, Level 16, State 1, Line 2 The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION.
Điều này sẽ xảy ra nếu SET IMPLICIT_TRANSACTIONS
của bạn OFF
. Xem bên dưới để biết điều gì sẽ xảy ra khi SET IMPLICIT_TRANSACTIONS
ON
.
Ví dụ về Lỗi do Xử lý Lỗi
Bạn có thể nhận được điều này do triển khai xử lý lỗi và quên rằng bạn đã cam kết hoặc khôi phục giao dịch ở nơi khác trong mã của bạn.
Ví dụ:
BEGIN TRANSACTION
BEGIN TRY
INSERT INTO Orders ( OrderId, OrderDate, CustomerId )
VALUES ( 5006, SYSDATETIME(), 1006 );
INSERT INTO OrderItems ( OrderId, OrderItemId, ProductId, Quantity, ItemPrice )
VALUES ( 5006, 1, 1, 20, 25.99 );
INSERT INTO OrderItems ( OrderId, OrderItemId, ProductId, Quantity, ItemPrice )
VALUES ( 5006, 2, 7, 120, 9.99 );
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION;
END CATCH
COMMIT TRANSACTION;
Kết quả:
(1 row affected) (1 row affected) (1 row affected) Msg 3902, Level 16, State 1, Line 20 The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION.
Trong trường hợp này, tôi đã có COMMIT TRANSACTION
trong TRY
khối. Vì vậy, đến thời điểm COMMIT TRANSACTION
thứ hai đã gặp phải, giao dịch đã được cam kết.
Chúng tôi sẽ thấy như vậy ngay cả khi giao dịch gặp lỗi và được khôi phục. Việc khôi phục sẽ kết thúc giao dịch và do đó, không có COMMIT
nào nữa câu lệnh là bắt buộc.
Vì vậy, để khắc phục sự cố này, chúng tôi chỉ cần xóa COMMIT TRANSACTION
cuối cùng và mã giao dịch sẽ giống như sau:
BEGIN TRANSACTION
BEGIN TRY
INSERT INTO Orders ( OrderId, OrderDate, CustomerId )
VALUES ( 5006, SYSDATETIME(), 1006 );
INSERT INTO OrderItems ( OrderId, OrderItemId, ProductId, Quantity, ItemPrice )
VALUES ( 5006, 1, 1, 20, 25.99 );
INSERT INTO OrderItems ( OrderId, OrderItemId, ProductId, Quantity, ItemPrice )
VALUES ( 5006, 2, 7, 120, 9.99 );
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION;
END CATCH
Giao dịch ngầm định
Nếu bạn đã bật các giao dịch ngầm định, bạn có thể nhận được các kết quả khác với ví dụ đầu tiên.
Nếu chúng tôi đặt IMPLICIT_TRANSACTIONS
thành ON
, đây là những gì chúng tôi nhận được:
SET IMPLICIT_TRANSACTIONS ON;
SELECT ProductName, ProductPrice FROM Products;
COMMIT TRANSACTION;
Kết quả:
+---------------------------------+----------------+ | ProductName | ProductPrice | |---------------------------------+----------------| | Left handed screwdriver | 25.99 | | Long Weight (blue) | 14.75 | | Long Weight (green) | 11.99 | | Sledge Hammer | 33.49 | | Chainsaw | 245.00 | | Straw Dog Box | 55.99 | | Bottomless Coffee Mugs (4 Pack) | 9.99 | +---------------------------------+----------------+ (7 rows affected)
Không có lỗi nào xảy ra.
Điều này là do, các câu lệnh T-SQL nhất định sẽ tự động bắt đầu một giao dịch khi chúng chạy. Như thể chúng được đặt trước bởi một BEGIN TRANSACTION
vô hình tuyên bố.
Khi IMPLICIT_TRANSACTIONS
OFF
, các câu lệnh này được cam kết tự động. Như thể họ đã thành công nhờ một COMMIT TRANSACTION
vô hình tuyên bố. Trong trường hợp này, giao dịch ở chế độ tự động gửi.
Khi IMPLICIT_TRANSACTIONS
ON
, không có COMMIT TRANSACTION
ẩn tuyên bố. Các câu lệnh này vẫn được bắt đầu bởi BEGIN TRANSACTION
ẩn , nhưng chúng cần được kết thúc một cách rõ ràng.
Một giao dịch ngầm vẫn được tiến hành cho đến khi nó được cam kết rõ ràng hoặc được khôi phục một cách rõ ràng.
Do đó, trong ví dụ này, COMMIT TRANSACTION
đi lạc của chúng tôi thực sự cần thiết để kết thúc giao dịch ngầm.