【问题标题】:Using Transactions - Best practices使用事务 - 最佳实践
【发布时间】:2018-09-25 17:49:15
【问题描述】:

假设我在SQL服务器中有一个程序为:

create procedure BULKINSERT
AS
 INSERT INTO TABLEB (
 SELECT NAME, ID From TableA
)
GO   

一个简单的从 TABLE A 读取数据并插入 TABLE B。如果我有 100 万条记录要插入到表 B 中,并且一条记录由于某种原因失败,在这种情况下我应该使用 TRANSACTION 还是不使用?

我应该回滚整个操作吗?

【问题讨论】:

  • 在交易中使用TRY CATCH
  • 由于一个 statement 始终被认为是原子的,并且您这里只有 1 条语句,因此要么将 100 万条记录插入到 TABLEB 中,要么没有。但是,如果发生错误,您可能需要处理错误,在这种情况下,您应该将 INSERT 放入 TRY 块并添加一个 CATCH 以处理发生错误时的处理方式。
  • @MK_ 你是对的。您应该发表您的评论作为答案。

标签: sql-server tsql stored-procedures transactions


【解决方案1】:

您可以为您的存储过程使用以下模板:

SET NOCOUNT, XACT_ABORT ON;

    BEGIN TRY

        BEGIN TRANSACTION;
        -- CODE BLOCK GOES HERE
        COMMIT TRANSACTION;

    END TRY
    BEGIN CATCH 

       IF @@TRANCOUNT > 0
       BEGIN
          ROLLBACK TRANSACTION
       END;

       -- GET ERRORS DETAILS OR THROW ERROR

    END CATCH;

SET NOCOUNT, XACT_ABORT OFF;

更多细节:

  • XACT_ABORT - 指定当 Transact-SQL 语句引发运行时错误时 SQL Server 是否自动回滚当前事务;

  • 如果您需要有关错误的信息(ERROR_MESSAGE、ERROR_LINE、ERROR_NUMBER、ERROR_PROCEDURE、ERROR_SEVERITY、ERROR_STATE)

这是处理事务的通用技术。推荐Erland Sommarskog的以下文章:

  1. Error and Transaction Handling in SQL Server Part One – Jumpstart Error Handling
  2. Error and Transaction Handling in SQL Server Part Two – Commands and Mechanisms

【讨论】:

    【解决方案2】:

    由于一个 语句 始终被认为是原子的,并且您这里只有 1 条语句,因此要么将 100 万条记录插入到 TABLEB 中,要么没有。但是,如果发生错误,您可能需要处理错误,在这种情况下,您应该将 INSERT 放入 TRY 块并添加一个 CATCH 以处理发生错误时的处理方式。

    要了解有关该主题的更多信息,请查看以下资源以获得良好的起点:

    【讨论】:

      【解决方案3】:

      如上所述,单个语句是一个事务。

      对 TABLEB 的主键上的插入进行排序以减慢碎片。

      需要注意的一件事是多次插入相同的数据。
      如果您想防止这种情况发生,请在 pk 上加入。

      declare @Ta table (id int identity primary key, name varchar(10));
      declare @Tb table (id int          primary key, name varchar(10));
      insert into @Ta values ('name'), ('name'), ('name'), ('name'), ('name'), ('name'), ('name'), ('nameL');
      
      insert into @Tb (id, name)
      select id, name from @Ta order by id;
      
      select * from @Tb;
      
      insert into @Tb (id, name)
      select ta.id, ta.name 
      from @Ta ta 
      left join @Tb tb 
        on tb.id = ta.id 
      where tb.id is null 
      order by ta.id;
      
      select * from @Tb;
      

      如果要更新合并命令上存在的搜索数据。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-26
        • 1970-01-01
        • 1970-01-01
        • 2011-12-16
        • 1970-01-01
        相关资源
        最近更新 更多