Bri*_*n B 15 sql-server transactions nested-transactions
我有一个存储过程需要设置一个保存点,以便在某些情况下,它可以撤消它所做的一切,并将错误代码返回给调用者,或接受/提交它并将成功返回给调用者.但无论调用者是否已经开始交易,我都需要它.该文件在这个问题上非常混乱.这是我认为可行的,但我不确定所有的后果.
问题是 - 这Stored Procedure (SP)是其他人所称的.所以我不知道他们是否已经开始交易......即使我要求用户开始使用我的SP交易,我仍然对正确使用Save Points...的问题有疑问
我的SP将测试交易是否正在进行,如果没有,请启动一个BEGIN TRANSACTION.如果一个事务正在进行中,它将改为创建一个保存点SAVE TRANSACTION MySavePointName,并保存这就是我所做的事实.
然后,如果我必须回滚我的更改,如果我BEGIN TRANSACTION早点做了,那么我会ROLLBACK TRANSACTION.如果我做了保存点,那么我会ROLLBACK TRANSACTION MySavePointName.这种情况似乎很有效.
这是我有点困惑的地方 - 如果我想保留我已经完成的工作,如果我开始一个事务,我将执行COMMIT TRANSACTION.但是如果我创建了保存点?我试过COMMIT TRANSACTION MySavePointName,但然后调用者尝试提交其事务并收到错误:
COMMIT TRANSACTION请求没有相应的BEGIN TRANSACTION.
所以我当时想知道 - 可以回滚一个保存点(这样可行:ROLLBACK TRANSACTION MySavePointName不会回滚调用者的事务).但也许人们永远不需要"承诺"它?它只是停留在那里,以防你需要回滚它,但一旦原始事务提交(或回滚)就会消失?
如果有一种"更好"的方式来"嵌套"交易,请也提供一些建议.我还没有弄清楚如何嵌套BEGIN TRANSACTION但只是回滚或提交我的内部事务.似乎ROLLBACK总会回滚到顶层事务,而COMMIT只是递减@@trancount.
Bri*_*n B 23
我相信我现在已经想到了这一切,所以我会回答我自己的问题......
如果你想在http://geekswithblogs.net/bbiales/archive/2012/03/15/how-to-nest-transactions-nicely---quotbegin-transactionquot-vs-quotsave获取更多细节,我甚至在博客上写了我的发现.的.aspx
所以我的SP从这样的东西开始,如果没有,则启动一个新的事务,但是如果一个正在进行中则使用一个保存点:
DECLARE @startingTranCount int
SET @startingTranCount = @@TRANCOUNT
IF @startingTranCount > 0
SAVE TRANSACTION mySavePointName
ELSE
BEGIN TRANSACTION
-- …
Run Code Online (Sandbox Code Playgroud)
然后,当准备提交更改时,您只需要在我们自己启动事务时提交:
IF @startingTranCount = 0
COMMIT TRANSACTION
Run Code Online (Sandbox Code Playgroud)
最后,到目前为止回滚您的更改:
-- Roll back changes...
IF @startingTranCount > 0
ROLLBACK TRANSACTION MySavePointName
ELSE
ROLLBACK TRANSACTION
Run Code Online (Sandbox Code Playgroud)
Chr*_*ers 12
扩展Brian B的答案.
这可确保保存点名称是唯一的,并使用SQL Server 2012的新TRY/CATCH/THROW功能.
DECLARE @mark CHAR(32) = replace(newid(), '-', '');
DECLARE @trans INT = @@TRANCOUNT;
IF @trans = 0
BEGIN TRANSACTION @mark;
ELSE
SAVE TRANSACTION @mark;
BEGIN TRY
-- do work here
IF @trans = 0
COMMIT TRANSACTION @mark;
END TRY
BEGIN CATCH
IF xact_state() = 1 OR (@trans = 0 AND xact_state() <> 0) ROLLBACK TRANSACTION @mark;
THROW;
END CATCH
Run Code Online (Sandbox Code Playgroud)
我在我的存储过程中使用了这种类型的事务管理器:
CREATE PROCEDURE Ardi_Sample_Test
@InputCandidateID INT
AS
DECLARE @TranCounter INT;
SET @TranCounter = @@TRANCOUNT;
IF @TranCounter > 0
SAVE TRANSACTION ProcedureSave;
ELSE
BEGIN TRANSACTION;
BEGIN TRY
/*
<Your Code>
*/
IF @TranCounter = 0
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
IF @TranCounter = 0
ROLLBACK TRANSACTION;
ELSE
IF XACT_STATE() <> -1
ROLLBACK TRANSACTION ProcedureSave;
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
SELECT @ErrorMessage = ERROR_MESSAGE();
SELECT @ErrorSeverity = ERROR_SEVERITY();
SELECT @ErrorState = ERROR_STATE();
RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState);
END CATCH
GO
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
28458 次 |
| 最近记录: |