嵌套存储过程中事务之间的关系?

发布于 2025-01-02 03:13:02 字数 543 浏览 1 评论 0原文

我把交易放在我所有的“设定”程序中。没问题。一切正常。

在这种情况下,我需要一个设定的过程,谢天谢地,只调用另一个过程一次,否则可能会让事情变得更加复杂。

所以快乐的沐浴就是这样。

  • 我在 ProcA 中并开始交易。
  • 它调用 ProcB 并启动一个事务。
  • ProcB 成功并提交。
  • ProcA 成功并提交。

但是,如果 ProcB 失败、回滚并重新抛出错误,会发生什么情况。它应该也会导致 ProcA 回滚,对吗?

如果 ProcB 成功并提交,然后 ProcA 随后失败并回滚怎么办……ProcB 中发生的事情会回滚吗?或者它是否已承诺?

我需要这两者一起工作,要么都成功,要么失败并且都回滚。确保这种情况发生的最佳方法是什么?

我正在使用 Microsoft SQL Server 2008 R2 (SP1)

注意:如果 ProcB 需要事务,因为可以在没有 ProcA 包装它的情况下调用它。从技术上讲,ProcA 并不总是调用 ProcB(取决于输入)。

I put transactions in all my "set" procedures. No problems. Everything works.

In this case, I need one set procedure, to call another, thankfully, only once, or that would potentially complicate things further.

So the happy bath would be.

  • I'm in ProcA and start a transaction.
  • It calls ProcB and it starts a transaction.
  • ProcB is successful and commits.
  • ProcA is successful and commits.

However, what happens if ProcB fails, rollsback, and rethrows the error. It should cause ProcA to rollback as well correct?

What if ProcB succeeds, commits, then ProcA subsequently fails, and rollsback...will what happened in ProcB be rolled back? or is it commited?

I need these two to work together, either both succeed, or fail and both be rolled back. What's the best way to ensure this happens?

I'm working with Microsoft SQL Server 2008 R2 (SP1)

Note: If ProcB requires a transaction because it can be called without ProcA wrapping it. And technically, ProcA won't always call ProcB (depends on input).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

晌融 2025-01-09 03:13:02

下面是一个简单的演示,展示了嵌套事务会发生什么:

CREATE TABLE TranTest (Field1 INTEGER)

BEGIN TRANSACTION
SELECT @@TRANCOUNT -- 1 open transaction
INSERT TranTest VALUES (1)

    BEGIN TRANSACTION
    SELECT @@TRANCOUNT -- 2 open transactions
    INSERT TranTest VALUES (2)
    ROLLBACK TRANSACTION -- this rolls back ALL transaction

SELECT @@TRANCOUNT -- 0 open transactions (you may have expected 1?)
SELECT * FROM TranTest -- No rows

如果您执行了 COMMIT TRANSACTION,而不是上面的 ROLLBACK,则实际上除了递减 @@TRANCOUNT 之外什么也不做。因此,您需要提交外部事务(这会将两行都提交到表中),或者执行 ROLLBACK ,这将导致没有行提交到表中。

以下是有关嵌套事务的 MSDN 参考: http://msdn.microsoft.com/en -us/library/ms189336.aspx

Here's a simple demo to show what happens with nested transations:

CREATE TABLE TranTest (Field1 INTEGER)

BEGIN TRANSACTION
SELECT @@TRANCOUNT -- 1 open transaction
INSERT TranTest VALUES (1)

    BEGIN TRANSACTION
    SELECT @@TRANCOUNT -- 2 open transactions
    INSERT TranTest VALUES (2)
    ROLLBACK TRANSACTION -- this rolls back ALL transaction

SELECT @@TRANCOUNT -- 0 open transactions (you may have expected 1?)
SELECT * FROM TranTest -- No rows

Instead f the ROLLBACK above, if you did a COMMIT TRANSACTION, this actual does nothing other then decrement @@TRANCOUNT. So you then would need to to either COMMIT the outer transaction (which would COMMIT both rows to the table), or do a ROLLBACK which would result in no rows being committed to the table.

Here's the MSDN ref on nested transactions: http://msdn.microsoft.com/en-us/library/ms189336.aspx

半步萧音过轻尘 2025-01-09 03:13:02

只需使用 XACT_ABORT ON 即可。运行以下脚本并亲自查看:

CREATE DATABASE ak_test;
GO
USE ak_test;
GO
CREATE TABLE dbo.a(i INT CONSTRAINT a_CannotInsertNegative CHECK(i>=0));
GO
CREATE TABLE dbo.b(i INT CONSTRAINT b_CannotInsertNegative CHECK(i>=0));
GO

CREATE PROCEDURE dbo.innerProc @i INT
AS
SET XACT_ABORT ON ;
BEGIN TRAN
INSERT b(i)VALUES(@i);
COMMIT;
GO

CREATE PROCEDURE dbo.outerProc @i1 INT, @i2 INT, @i3 INT
AS
SET XACT_ABORT ON ;
BEGIN TRAN
INSERT a(i)VALUES(@i1);
EXEC innerProc @i=@i2;
INSERT a(i)VALUES(@i3);
COMMIT;
GO

-- succeeds
EXEC dbo.outerProc 1, 2, 3;
SELECT * FROM dbo.a;
SELECT * FROM dbo.b;
GO
-- inner proc fails
EXEC dbo.outerProc 2, -3, 4;
GO
SELECT * FROM dbo.a;
SELECT * FROM dbo.b;
GO
-- second insert in outer proc fails
EXEC dbo.outerProc 3, 4, -5;
GO
SELECT * FROM dbo.a;
SELECT * FROM dbo.b;

Just use XACT_ABORT ON, and you are all set. Run the following script and see for yourself:

CREATE DATABASE ak_test;
GO
USE ak_test;
GO
CREATE TABLE dbo.a(i INT CONSTRAINT a_CannotInsertNegative CHECK(i>=0));
GO
CREATE TABLE dbo.b(i INT CONSTRAINT b_CannotInsertNegative CHECK(i>=0));
GO

CREATE PROCEDURE dbo.innerProc @i INT
AS
SET XACT_ABORT ON ;
BEGIN TRAN
INSERT b(i)VALUES(@i);
COMMIT;
GO

CREATE PROCEDURE dbo.outerProc @i1 INT, @i2 INT, @i3 INT
AS
SET XACT_ABORT ON ;
BEGIN TRAN
INSERT a(i)VALUES(@i1);
EXEC innerProc @i=@i2;
INSERT a(i)VALUES(@i3);
COMMIT;
GO

-- succeeds
EXEC dbo.outerProc 1, 2, 3;
SELECT * FROM dbo.a;
SELECT * FROM dbo.b;
GO
-- inner proc fails
EXEC dbo.outerProc 2, -3, 4;
GO
SELECT * FROM dbo.a;
SELECT * FROM dbo.b;
GO
-- second insert in outer proc fails
EXEC dbo.outerProc 3, 4, -5;
GO
SELECT * FROM dbo.a;
SELECT * FROM dbo.b;
甜是你 2025-01-09 03:13:02

我对事务很偏执(有一次该事务在生产中处于打开状态,半小时内没有人注意到......)所以我会像这样扭曲潜在内部事务:

CREATE PROCEDURE etcetc

...

DECLARE @IsTransaction bit = 0

IF @@trancount > 0
 BEGIN
    BEGIN TRANSACTION
    SET @IsTransaction = 1
 END

...

IF @IsTransaction = 1
 BEGIN
    COMMIT
    --  or ROLLBACk, as necessary
 END

所有事务处理(以及处理事务中发生的错误)必须在启动事务的任何级别进行处理。

(还有其他人注意到 BOL 实际上并没有说明当您向非最外层事务的指定事务发出 ROLLBACK 时会发生什么吗?他们确实阐明了所有其他排列......)

I'm paranoid about transactions (there was this transaction left open on Production once that no one noticed for half an hour...) so I'd warp the potentially inner transaction like so:

CREATE PROCEDURE etcetc

...

DECLARE @IsTransaction bit = 0

IF @@trancount > 0
 BEGIN
    BEGIN TRANSACTION
    SET @IsTransaction = 1
 END

...

IF @IsTransaction = 1
 BEGIN
    COMMIT
    --  or ROLLBACk, as necessary
 END

All transaction processing (and handling of errors that occur within the transaction) must then be dealt with at whatever level launched the transaction.

(And did anyone else notice how BOL doesn't actually say what happens when you issue a ROLLBACK to a named transaction that isn't the outermost transaction? They do spell out every other permutation...)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文