SQL Server:批处理语句全部作为一个事务执行?

时间:2018-08-22 17:17:05

标签: sql-server

所以我运行了带有一堆UPDATE语句的SQL批处理:

UPDATE...;    
UPDATE...;    
UPDATE...;

结果表明批处理是作为单个事务运行的,因此创建了许多锁(我们的数据库监视软件清楚地表明这是一个大事务),因此,显然类似于我围绕该批处理写BEGIN ... COMMIT:

BEGIN TRANS;    
UPDATE...;    
UPDATE...;    
UPDATE...;    
COMMIT;

真的是这样吗?批次是否总是作为一个事务执行? (我不是处于“显式事务”模式),为什么要这样做,可以对其进行配置,还是仅仅是SQL Server的行为?

如果我将每条语句都包装在BEGIN..COMMIT中,它将发生什么变化?

BEGIN TRANS;
UPDATE...;
COMMIT;     
BEGIN TRANS;
UPDATE...;
COMMIT;     
BEGIN TRANS;
UPDATE...;
COMMIT; 

谢谢!

1 个答案:

答案 0 :(得分:0)

假设您正在从SSMS查询窗口执行更新,则可以将代码重构为

BEGIN TRANS;    
UPDATE...;
GO    
UPDATE...;
GO    
UPDATE...;
GO    
COMMIT;

GO将使每个UPDATE按调用的顺序在其自己的批处理中优先执行,但是直到最后一次COMMIT调用时才会提交。

我已经通过以下示例对此进行了测试,您可以在SSMS中自行运行。

SET NOCOUNT ON
GO

IF EXISTS ( SELECT * FROM sys.tables WHERE name = 'BatchTest' )
    DROP TABLE dbo.BatchTest;
GO

CREATE TABLE dbo.BatchTest (
    id INT IDENTITY (1,1) PRIMARY KEY NOT NULL
    , col1 VARCHAR(50)
    , col2 VARCHAR(50)
    , col3 VARCHAR(50)
    , col4 VARCHAR(50)
)
GO

DECLARE @i INT = 1;
WHILE ( @i <= 100 ) BEGIN
    INSERT INTO dbo.BatchTest ( col1 ) VALUES ( 'col1_' + CAST ( @i AS VARCHAR(10) ) );
    SET @i += 1;
END
GO

SELECT * FROM dbo.BatchTest ORDER BY id;

/*
    -- test tran/commit --
    -- manually select and execute the code below after the BatchTest has been created and populated with data --

    SET NOCOUNT ON
    GO

    BEGIN TRAN;
    UPDATE dbo.BatchTest SET col2 = 'col2_' + CAST ( id AS VARCHAR(10) );
    GO
    UPDATE dbo.BatchTest SET col3 = 'col3_' + CAST ( id AS VARCHAR(10) );
    GO
    UPDATE dbo.BatchTest SET col4 = 'col4_' + CAST ( id AS VARCHAR(10) );
    GO
    --COMMIT;
    ROLLBACK;

    SELECT * FROM dbo.BatchTest ORDER BY id;

*/

请注意代码中有关选择和执行tran / commit测试的注释。

单个ROLLBACK撤消当前事务中的所有UPDATE,而与使用GO无关,而COMMIT将全部提交它们。显然,您应该多加努力,对数据进行测试,但这可能会有助于解决锁定问题。

有关SQL Server使用GO及其意图的一些后续阅读: https://docs.microsoft.com/en-us/sql/t-sql/language-elements/sql-server-utilities-statements-go?view=sql-server-2017