【问题标题】:will this approach work for executing ddl in a transaction?这种方法是否适用于在事务中执行 ddl?
【发布时间】:2018-04-06 19:32:22
【问题描述】:

我正在为我的数据库中的所有对象创建 DDL,以便传播到上层环境。我想确保一个全有或全无的事务,包括所有数据库对象的创建/更改和数据加载插入。是这么简单还是有什么注意事项?

BEGIN TRANSACTION

-- include create script generated from ssms

-- include insert data load scripts

COMMIT

我通常只将事务用于多表插入等。

【问题讨论】:

标签: sql sql-server tsql ssms


【解决方案1】:

试试这个:

USE [DatabaseName]
GO

BEGIN TRANSACTION Tran1
    BEGIN TRY
        INSERT ...
        COMMIT TRANSACTION Tran1
    END TRY
    BEGIN CATCH
        -- ROLLBACK first.
        ROLLBACK TRANSACTION Tran1
    END CATCH
GO

请注意,如果此操作失败并且任何具有身份的表在其中插入了数据但随后回滚,则需要重新设置身份值。出于某种原因,Identity 值的递增发生在事务之外。

【讨论】:

  • 考虑到并发事务也可以增加这个值并提交它们的工作,它会回滚到什么位置?最后使用的身份值只不过是元数据。
  • 身份值不会回滚。如果需要,您需要使用 RESEED 命令手动回滚。
  • 是的,很明显。我的意思是你说“出于某种原因”。原因是,在 ROLLBACK 事件中,服务器无法回滚 IDENTITY 列。我向您提出了一个问题:在已经提交的并发事务存在的情况下,它会回滚到什么位置?
  • 顺便说一句,IDENTITY 的回滚行为与 OP 的问题无关,因为 OP 也在同一事务中执行 DDL。因此,无论如何,当事务回滚时,这些表都会消失。
  • 我明白你在问什么。可以在交易前获取当前身份的最大值,然后以最大值重新播种到 catch 块中。
【解决方案2】:

是的,您通常在事务中同时执行 DDL 和 DML 以确保全有或全无。但是,某些 DDL(例如 CREATE DATABASE)不能在事务中执行,而其他 DDL(例如 CREATE SCHEMA)必须是批处理中的唯一语句。

除非有这些限制,否则您可以在 T-SQL 脚本中使用事务和结构化错误处理:

SET XACT_ABORT ON;
BEGIN TRY
    BEGIN TRANSACTION;

    -- include create script generated from ssms

    -- include insert data load scripts

    COMMIT;
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0 ROLLBACK;
    THROW;
END;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多