Máy chủ Sql: Một hành vi có vẻ kỳ lạ của BEGIN TRAN - CAM KẾT


7

Đầu tiên tạo hai bảng:

CREATE TABLE xyz (Id INT)
CREATE TABLE abc (Id INT)

Vui lòng quan sát mã SQL sau:

DELETE FROM abc
BEGIN TRAN
EXEC('
INSERT INTO xyz VALUES (1),(2)
DECLARE @x INT = (SELECT Id FROM xyz)
')
INSERT INTO abc VALUES (1)
COMMIT

SELECT * FROM abc

Chạy nó xuất ra lỗi sau:

Msg 512, Level 16, State 1, Line 3
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.

Và không có kết quả . Tất cả như mong đợi.

Bây giờ chúng ta hãy thay đổi lỗi thành lỗi cú pháp bằng cách thay thế xyz)bằng xyz. Đây là lỗi:

Msg 102, Level 15, State 1, Line 3
Incorrect syntax near 'xyz'.

Nhưng lần này có một kết quả:

nhập mô tả hình ảnh ở đây

Tại sao? Chuyện gì đang xảy ra vậy?


5
Bạn có thể giải thích lý do tại sao bạn giới thiệu lại câu hỏi này ?
Aaron Bertrand

Tôi không chắc đâu là diễn đàn phù hợp - SO hay DBA. Đánh giá về số lượt xem đăng nó trên SO có lẽ là một sai lầm ở nơi đầu tiên.
đánh dấu

Câu trả lời:


6

Bạn có thể kiểm soát hành vi của ví dụ đầu tiên của mình bằng cách chỉ định:

SET XACT_ABORT ON

Ở đầu tập lệnh của bạn, sau đó bạn không nhận được kết quả. Bạn nhận được một kết quả như bạn mô tả nếu bạn chỉ định SET XACT_ABORT OFF.

Lý do cho các hành vi khác nhau là ví dụ thứ hai "thay thế xyz)bằng xyz" chứa lỗi cú pháp tức là lô EXEC được phân tích cú pháp, lỗi cú pháp được phát hiện và lô không chạy. EXEC là một lô riêng biệt (đây là lý do bạn không thể xác định các biến bên ngoài EXEC và tham chiếu chúng bên trong) và quá trình xử lý tiếp tục với phần còn lại của giao dịch.

Đối với ví dụ đầu tiên " (SELECT Id FROM xyz)", đây là cú pháp hợp lệ, do đó, phân tích cú pháp chính xác. Lỗi chỉ được tìm thấy trong thời gian chạy và xử lý tiếp tục nếu SET XACT_ABORT OFFnhưng dừng nếu SET XACT_ABORT ON.


Có cách nào để xử lý tất cả các lỗi giống nhau mà không cần dùng đến BEGIN TRY-END CATCH, sử dụng kết quả trong một mã dài hơn - người ta phải quay lại bằng tay (Internet nói rằng tôi cần kiểm tra @@TRANCOUNTtrước khi thực hiện) và sửa lại lỗi ban đầu sử dụng THROW. Mã nhiều.
đánh dấu

9

Hành vi phụ thuộc vào SET XACT_ABORT và được giải thích trong trích dẫn sau từ bài viết được liên kết.

Khi SET XACT_ABORT BẬT, nếu câu lệnh Transact-SQL xuất hiện lỗi thời gian chạy, toàn bộ giao dịch bị chấm dứt và được khôi phục.

Khi SET XACT_ABORT TẮT, trong một số trường hợp, chỉ có câu lệnh Transact-SQL gây ra lỗi được khôi phục và giao dịch tiếp tục xử lý. Tùy thuộc vào mức độ nghiêm trọng của lỗi, toàn bộ giao dịch có thể được khôi phục ngay cả khi SET XACT_ABORT bị TẮT. TẮT là cài đặt mặc định.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.