Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 如何避免在嵌套存储过程中的嵌套事务中使用重复的保存点名称?_Sql_Sql Server_Tsql_Transactions - Fatal编程技术网

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