Trong hành trình tìm kiếm không ngừng nghỉ của mình để tự bắn vào chân mình bằng giao dịch tiết kiệm, tôi dường như đã tìm thấy nhiều cách hơn để hoàn thành mục đích tìm kiếm. Điều khoản giao dịch lưu chính lần này là không cần thiết, nhưng đó là vì tôi đã viết mã dưới đây.
Xem xét ví dụ đầy đủ sau đây với các trình xử lý lỗi lồng nhau:
begin try
begin try
select 'Step 1';
end try
begin catch
select 'Step 1 handler - handling ''' + error_message() + '''';
goto commit_and_exit;
end catch;
begin try
select 'Step 2';
raiserror('Step 2 error', 16, 1);
end try
begin catch
select 'Step 2 handler - handling ''' + error_message() + '''';
goto commit_and_exit;
end catch;
end try
begin catch
select 'Outer handler - handling ''' + error_message() + '''';
goto commit_and_exit;
end catch
commit_and_exit:
raiserror('Error raised for the caller to see', 16, 1);
Nó được ghi lại rằng
GOTO
các câu lệnh có thể được sử dụng để chuyển đến một nhãn bên trong cùngTRY
hoặcCATCH
chặn hoặc để lại mộtTRY
hoặc mộtCATCH
khối.
Hay nó có thể?
Với mã ở trên, một lập trình viên lành mạnh sẽ cho biết đầu ra sẽ là
Bước 1
Bước 2
Trình xử lý bước 2 - xử lý 'Lỗi bước 2'
<Lỗi được đưa ra để người gọi thấy>
Trong thực tế những gì đang xảy ra là:
Bước 1
Bước 2
Trình xử lý bước 2
- xử lý 'Lỗi bước 2' Trình xử lý bên ngoài - xử lý 'Lỗi được đưa ra cho người gọi để xem'
<Lỗi đưa ra cho người gọi để xem>
Khi gỡ lỗi từng bước, tôi có thể thấy điều khiển đó hoàn toàn rời khỏi khối thử / bắt, sau đó xảy ra lỗi, điều khiển được đưa trở lại catch
khối ngoài cùng , khối đó thực thi, điều khiển lại chuyển sang commit_and_exit:
và khối cuối cùng được thực thi một lần nữa .
Nếu bạn có một số commit tran
s hoặc rollback trans
s commit_and_exit:
, bạn sẽ cố gắng thực hiện tran hai lần. Với kết quả có thể tưởng tượng, thực tế có thể có các giao dịch bên ngoài được bắt đầu bởi người gọi.
Tôi cũng đã thử tạo một nhãn khác end_of_outer:
, ngay trước lớp ngoài end try
, để điều khiển rời khỏi try
khối bên ngoài "bình thường". Đủ thú vị, điều đó đã không làm cho bất kỳ sự khác biệt.
Cái quái gì đang xảy ra, và cách làm đúng là gì?
XACT_STATE() = 1
, do đó chúng tôi quay lại điểm lưu và tiếp tục). Nhưng tôi quan tâm nhiều hơn đến chính nguyên tắc xử lý lỗi ở đây, ngay cả khi có giao dịch. Bất kỳ mã sau commit_and_exit:
sẽ thực hiện hai lần.