我有一个包含BEGIN TRANSACTION
和COMMIT TRANSACTION
语句的存储过程。在事务中是选择查询WITH(XLOCK, ROWLOCK)
。
如果提供了超出边界值的某些计算会导致算术溢出错误,则事务可能会失败。在任何插入/更新语句之前都会发生此错误。
我的问题是,我应该将事务包装在TRY / CATCH中并回滚,还是这不是真的需要,如果事务失败,所有锁都会自动释放?我唯一担心的是,如果事务失败,SQL不会释放事务的所有锁。
谢谢,
汤姆
答案 0 :(得分:8)
更简单的方法是:
set xact_abort on
这将导致在发生错误时自动回滚事务。
示例代码:
set xact_abort on
begin transaction
select 1/0
go
print @@trancount -- Prints 0
set xact_abort off
begin transaction
select 1/0
go
print @@trancount -- Prints 1
如果您多次执行第二段,您会看到交易计数增加到2,3,4等。第一段的单次运行会重置所有交易。
答案 1 :(得分:6)
简短回答:是的。
每当我使用BEGIN TRANSACTION时,总是包括使用错误处理和ROLLBACK。遇到意外(和/或无法预料的 - 您无法知道将来可能需要修改代码的情况)的情况会导致生产服务器上的开放事务过于严重而无法执行此操作。
在SQL Server 2000及更早版本中,您必须使用@@ Error逻辑。在SQL 2005及更高版本中,您可以使用(远优于)TRY ... CATCH ...语法。
答案 2 :(得分:5)
我喜欢布拉德的方法,但它需要一点点清理,以便您可以看到导致问题的错误。
begin try
begin transaction;
...
commit transaction;
end try
begin catch
declare @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int;
select @ErrorMessage = ERROR_MESSAGE() + ' Line ' + cast(ERROR_LINE() as nvarchar(5)), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE();
rollback transaction;
raiserror (@ErrorMessage, @ErrorSeverity, @ErrorState);
end catch
答案 3 :(得分:3)
TRY/CATCH
不是必需来释放锁定。但是,我认为以下模板对大多数交易都有好处。
BEGIN TRY
BEGIN TRAN
...
IF (@@error <> 0)
ROLLBACK TRAN
END TRY
BEGIN CATCH
ROLLBACK TRAN
END CATCH
--BEGIN FINALLY (doesnt exist, which is why I commented it out)
IF (@@trancount > 0)
COMMIT TRAN
--END FINALLY
答案 4 :(得分:1)
begin transaction; -- you don't want to hit catch block if begin transaction will fail
begin try
... updates/inserts/selects ...
commit transaction; -- the last statement in try code block is always commit
end try
begin catch
rollback transaction; -- first step before other error handling code is rollback transaction
declare @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int;
select @ErrorMessage = ERROR_MESSAGE() + ' Line ' + cast(ERROR_LINE() as nvarchar(5)), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE();
raiserror (@ErrorMessage, @ErrorSeverity, @ErrorState);
end catch