相关SQL语句:
BEGIN TRAN
SAVE TRAN
COMMIT TRAN
ROLLBACK TRAN
嵌套事务示例:
BEGIN TRAN Tran1
BEGIN TRAN Tran2
- COMMIT TRAN 可以单独指定某个事务名,如Tran1,Tran2进行提交。其实也没什么效果,即使Tran2提交成功了,只要将外层事务Tran1回滚,Tran2保存的数据照样被回滚!
- ROLLBACK TRAN 不能指定某个事务名进行回滚!只能ROLLBACK TRAN 或者 ROLLBACK TRAN Tran1,也就说只能回滚最外层的事务名。如果执行ROLLBACK TRAN Tran2,SQL会提示“无法回滚 Tran2。找不到该名称的事务或保存点”,出错的原因就是因为Tran2不是最外层事务。总结一句话:ROLLBACK 要么就所有事务都回滚,要么就回滚时异常,一个事务都没回滚!
- ROLLBACK 可以回滚某个事务保存点(SAVE TRAN TranSave1), 如ROLLBACK TRAN TranSave1,但是要明白的是,回滚事务保存点并不会使事务数@TranCount减少,你嵌套了几个事务,它还是有几个事务数.
- 特别注意,如果在父存储过程创建一个事务Tran1,然后在子存储过程执行ROLLBACK TRAN后,子存储过程会抛出异常!事务只能在同一个存储过程里面创建、回滚和提交,不允许分离在不同的存储过程里面。
基于以上特点,我个人觉得嵌套事务的作用不大,SQL的内部处理其实最终就是处理一个最外层的事务点。SQL抛出事务相关的异常,并不是代码有何问题,而是在提醒我们注意事务的控制。 我们只要采用TRY CATCH 方式捕获相关异常就可以,我们只要确保设计的事务点能正常回滚或提交就OK了。
解决方法1:
TRY CATCH 捕获相关异常
解决方法2:
如果外部已经有事务了,就不再创建内部事务。我想SQL的事务异常提醒就是为了告诉你,不能随便一个地方放事务。
IF @TRANCOUNT =0
BEGIN TRAN
TRY CATCH 注意事项:
- SQL语句不加try catch,即使出现异常,后续的SQL语句也会执行。但是一旦外部加了try catch,则会捕获异常,导致后续的SQL语句没有执行。
- 是否SQL的异常有分致命和普遍的,在没加try catch的情况下,普通的可以继续往下走,但是致命的就不往下走了。这个和C#编程语言有重大的不同,编程语言一旦出现异常,后续代码就不再执行!
在处理嵌套事务时,要特别注意,不论如何要确保事务被完整的关闭或被回滚!
- 回滚比较好控制。无论有多少级事务数,只要ROLLBACK 一次就可以。不过如果是ROLLBACK TRAN TRANNAME,TranName不是第一级的话,则会出现异常,等于没有执行ROLLBACK操作。
- 提交就要特别注意了。BEGIN TRAN 创建事务3个,则必须COMMIT TRAN 提交事务3次,才能确保事务数被完整提交。可以通过@@TRANCOUNT来查看当前事务数。一旦存储过程没有完整提交事务,则可能出现事务锁表的情况!如果创建事务的进程销毁了,即使有未提交的事务,应该也销毁,算回滚了吧?