Sql 如何避免在嵌套存储过程中的嵌套事务中使用重复的保存点名称?
我有一个几乎总是遵循的模式,如果我需要在事务中结束操作,我会这样做:Sql 如何避免在嵌套存储过程中的嵌套事务中使用重复的保存点名称?,sql,sql-server,tsql,transactions,Sql,Sql Server,Tsql,Transactions,我有一个几乎总是遵循的模式,如果我需要在事务中结束操作,我会这样做: BEGIN TRANSACTION SAVE TRANSACTION TX -- Stuff IF @error <> 0 ROLLBACK TRANSACTION TX COMMIT TRANSACTION 当我执行此操作时,它会列出一条值为“1”的记录。换句话说,即使我回滚了外部事务,也会向表中添加一条记录 发生的情况是,外部级别的回滚事务TX正在回滚到内部级别的最后一个保存事务TX。现在我把这
BEGIN TRANSACTION
SAVE TRANSACTION TX
-- Stuff
IF @error <> 0
ROLLBACK TRANSACTION TX
COMMIT TRANSACTION
当我执行此操作时,它会列出一条值为“1”的记录。换句话说,即使我回滚了外部事务,也会向表中添加一条记录
发生的情况是,外部级别的回滚事务TX
正在回滚到内部级别的最后一个保存事务TX
。现在我把这些都写出来了,我可以看到它背后的逻辑:服务器正在通过日志文件进行回溯,将其视为线性事务流;它不理解事务嵌套(或者在我的真实场景中,通过调用其他存储过程)所隐含的嵌套/层次结构
因此,很明显,我需要开始使用唯一的保存点名称,而不是盲目地到处使用“TX”。但是——这就是我最终要说的——有没有一种方法可以以复制可复制的方式做到这一点,这样我仍然可以在任何地方使用相同的代码?我能以某种方式动态自动生成保存点名称吗?做这类事情有没有惯例或最佳实践
每次启动一个事务时,都要想出一个唯一的名称并不困难(可以基于SP名称或类似名称),但我确实担心最终会出现冲突——您不会知道,因为它只会悄悄地破坏您的数据,而不会导致错误…:-(查看文档:
看起来您可以根据变量对其命名,因此请尝试创建您的模式:
DECALRE @savepoint_variable varchar(1000)
SET @savepoint_variable=OBJECT_NAME(@@PROCID)+'|'+CONVERT(char(23),GETDATE(),121)
BEGIN TRANSACTION
SAVE TRANSACTION @savepoint_variable
-- Stuff
IF @error <> 0
BEGIN
ROLLBACK TRANSACTION @savepoint_variable
END
COMMIT TRANSACTION
decare@savepoint\u变量varchar(1000)
SET@savepoint_variable=OBJECT_NAME(+@@PROCID)+'|'+CONVERT(char(23),GETDATE(),121)
开始交易
保存事务@savepoint\u变量
--东西
如果@错误0
开始
回滚事务@savepoint\u变量
结束
提交事务
当从不同的过程调用时,@savepoint_变量将具有不同的局部值,您的回滚应该回滚正确的值。我在保存点名称中输入了当前日期时间,因为您可能在某个点使用递归,如果这是复制粘贴模式,则最好处理所有情况。同意KM的解决方案开 不过我更喜欢使用guid来生成唯一的保存点名称
DECLARE @savepoint AS VARCHAR(36)
SET @savepoint = CONVERT(VARCHAR(36), NEWID())
BEGIN TRANSACTION
SAVE TRANSACTION @savepoint
...
ROLLBACK TRANSACTION @savepoint
COMMIT TRANSACTION
是的,我可能确实更喜欢这样,因为它的代码看起来不那么难看,而且拥有一个“可读”的保存点名称并没有什么真正的好处,因为您从来没有看到过它们。请参阅我对KM的响应。@savepoint中超过32个字符将被忽略,留下一个截断的GUID。NEWID()长度为36个字符。其中正好有4个破折号。如果替换(NEWID(),“-”,“”),则正好得到32个字符并保留GUID的唯一性。:)是否值得在答案中添加该调整?特别是,最好将VARCHAR(36)更改为VARCHAR(32),以确保您不能复制粘贴该代码并忘记32个字符的限制…如果您进一步阅读此答案顶部的链接,您将看到“@savepoint\u变量。。。可以向变量传递32个以上的字符,但只会使用前32个字符。”这意味着转换(char(23),GETDATE(),121)很可能会从保存点名称(以及过程名称的结尾)中被截断。
DECALRE @savepoint_variable varchar(1000)
SET @savepoint_variable=OBJECT_NAME(@@PROCID)+'|'+CONVERT(char(23),GETDATE(),121)
BEGIN TRANSACTION
SAVE TRANSACTION @savepoint_variable
-- Stuff
IF @error <> 0
BEGIN
ROLLBACK TRANSACTION @savepoint_variable
END
COMMIT TRANSACTION
DECLARE @savepoint AS VARCHAR(36)
SET @savepoint = CONVERT(VARCHAR(36), NEWID())
BEGIN TRANSACTION
SAVE TRANSACTION @savepoint
...
ROLLBACK TRANSACTION @savepoint
COMMIT TRANSACTION