SQL Server 中事务的正确使用

Posted

技术标签:

【中文标题】SQL Server 中事务的正确使用【英文标题】:Correct use of transactions in SQL Server 【发布时间】:2012-04-26 13:46:53 【问题描述】:

我有 2 个命令,需要它们都正确执行或都不执行。所以我想我需要一个事务,但我不知道如何正确使用它。

以下脚本有什么问题?

BEGIN TRANSACTION [Tran1]

INSERT INTO [Test].[dbo].[T1]
    ([Title], [AVG])
VALUES ('Tidd130', 130), ('Tidd230', 230)

UPDATE [Test].[dbo].[T1]
  SET [Title] = N'az2' ,[AVG] = 1
  WHERE [dbo].[T1].[Title] = N'az'

COMMIT TRANSACTION [Tran1]
GO

INSERT命令执行了,但是UPDATE命令有问题。

如果其中任何一个命令在执行过程中出现错误,我该如何实现它以回滚这两个命令?

【问题讨论】:

【参考方案1】:

添加一个try/catch块,如果事务成功则提交更改,如果事务失败则回滚事务:

BEGIN TRANSACTION [Tran1]

  BEGIN TRY

      INSERT INTO [Test].[dbo].[T1] ([Title], [AVG])
      VALUES ('Tidd130', 130), ('Tidd230', 230)

      UPDATE [Test].[dbo].[T1]
      SET [Title] = N'az2' ,[AVG] = 1
      WHERE [dbo].[T1].[Title] = N'az'

      COMMIT TRANSACTION [Tran1]

  END TRY

  BEGIN CATCH

      ROLLBACK TRANSACTION [Tran1]

  END CATCH  

【讨论】:

不应该把BEGIN TRANSACTION [Tran1]放在TRY里面吗?无论如何 - 非常简单和优雅的代码。 @PiotrNawrot 否,如果事务创建失败,则无需在 catch 中回滚。 如果您想查看错误,请将其包含在 catch 中:SELECT ERROR_MESSAGE() AS ErrorMessage; @KevinLeStarge 或简单的THROW;,如果您使用的是 SQL Server >= 2012,如上所述 here【参考方案2】:

在存储过程的开头应该输入SET XACT_ABORT ON 来指示Sql Server 自动回滚事务以防出错。如果省略或设置为 OFF,则需要在每个语句之后测试 @@ERROR 或使用 TRY ... CATCH rollback 块。

【讨论】:

换句话说,除非您先 SET XACT_ABORT ON,否则您的事务不是原子的。 带有下划线的url很难看,但是XACT_ABORT中有下划线【参考方案3】:

简单的方法:

CREATE TABLE T
(
    C [nvarchar](100) NOT NULL UNIQUE,
);

SET XACT_ABORT ON -- Turns on rollback if T-SQL statement raises a run-time error.
SELECT * FROM T; -- Check before.
BEGIN TRAN
    INSERT INTO T VALUES ('A');
    INSERT INTO T VALUES ('B');
    INSERT INTO T VALUES ('B');
    INSERT INTO T VALUES ('C');
COMMIT TRAN
SELECT * FROM T; -- Check after.
DELETE T;

【讨论】:

以上是关于SQL Server 中事务的正确使用的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 事务与锁

SQL Server中的事务与锁

SQL Server中的事务与锁

SQL Server中的事务与锁

SQL Server 中的事务和@@Error 函数

SQL Server中事务日志管理的步骤,第5级:完全恢复模式管理日志