SQLServer多事务——事务嵌套
在ERP中,偶尔会有存储过程里面继续调用存储过程的情况
其中更有一些特殊的存储过程分别都使用了存储过程,大致可以分为下面几种情况:
1.平行事务,在多个事务中,任意一个成功则提交数据库,失败则各自ROLLBACK
这种情况其实很简单,按顺序执行就可以了,前提是失败的存储过程不要raiserror,使用try catch捕获所有异常,通过则返回OK,失败则返回NG,即不在数据库层面抛出异常,返回一个结果集,有点类似于api调用返回结果,包含code 和 msg
2.按顺序执行,出错则回滚全部
比如我们要做一个BOM导入 ,首先需要先导入存货档案,之后再根据导入的存货档案生成BOM,如果导入存货档案的时候就失败了,那么直接回滚,同时,为保证一致性,我们在BOM导入失败时也要求回滚存货档案已经提交的信息(其实也可以先导存货档案再导BOM,但基于客户BOM和存货档案是融合在同一份EXCEL里面,所以做了一致性事务)
这个时候我们可以使用事务嵌套,下面有一个简单的示例:
CREATE TABLE #tmp1 (
id INT,
value NVARCHAR(10)
)
BEGIN TRY
BEGIN TRAN tr
BEGIN TRY
BEGIN TRAN tr1
SAVE TRAN point1
INSERT INTO #tmp1(id, value)VALUES(1, N'v1')
COMMIT TRAN
END TRY
BEGIN CATCH
ROLLBACK TRAN point1;COMMIT TRAN tr1;RAISERROR('cuowu111',16,1)
END CATCH
BEGIN TRY
BEGIN TRAN tr2
SAVE TRAN point2
RAISERROR('error',16,1)
COMMIT TRAN
END TRY
BEGIN CATCH
ROLLBACK TRAN point2;COMMIT TRAN tr2;RAISERROR('cuowu2222',16,1)
END CATCH
COMMIT TRAN tr
END TRY
BEGIN CATCH
ROLLBACK
END CATCH
这里使用到了SAVE TRAN point ,是因为在ROLLBACK的时候,会清空数据库中的全局变量@@trancount,而在数据库中,是以该变量判断是否存在事务的,所以当第二个commit或者rollback的时候一定会报错提交的数目不一致,报错信息:EXECUTE
后的事务计数指示
BEGIN
和
COMMIT
语句的数目不匹配。上一计数 = 1,当前计数 = 0。
使用save tran point 保存节点,最后出错回滚再回滚到该节点,然后提交,这时相当于提交了一个空事务,效果等同于回滚了整个子事务。最后通过一个整体的父事务去包含所有子事务,我们通过读取子事务的错误信息(原则上子事务也不向外抛出异常,使用结果集记录成功或失败信息),出错则人为raiserror一个异常 ,触发父事务进行回滚。这样就可以实现多个事务的嵌套
3.那如果我们想要自定义回滚内容呢?假设一种场景,我们需要多传入一个参数来决定子存储过程是否回滚,假设我给子存储过程A传入一个值为false的参数,意思是无论A是否会出错,都不会回滚A所执行的内容。给子存储过程B传入参数true,则表示B出错一定回滚。
其实这个原理类似存储过程嵌套,不过需要我们再save point上下点功夫(因为返回的是结果集而不是raiserror,所以可以人为定义规则判断是否需要回滚)
类似的还有 B commit的时候触发 A回滚(无论A是否成功) : B先执行 ,失败后进入A,成功后则A直接 不执行
ABCDE,E出错,回滚到C:在C处定义一个point,E出错直接回滚到此处(待测试)
最后,可能有人会问那不使用嵌套事务不行吗?下一章我们讲另一个方法:内部事务与外部事务的统一
方法永远不止一个,但一定会有一个最适合的方法。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库