【问题标题】:Unexpected, non-intuitive behavior of BEGIN - COMMIT TRANSACTIONBEGIN - COMMIT TRANSACTION 的意外、非直觉行为
【发布时间】:2018-04-18 06:30:43
【问题描述】:

我写的是我几天前问的this question

适合我需要的答案是:

UPDATE ProcActivity SET IsActive = 1 WHERE ProcedureName = 'proc_name'
BEGIN TRANSACTION
EXEC proc_name
COMMIT TRANSACTION
UPDATE ProcActivity SET IsActive = 0 WHERE ProcedureName = 'proc_name'

现在这是另一个问题:

直觉上,我以为如果我将UPDATE 语句包装在BEGIN....COMMIT TRANSACTION 中,它会在到达COMMIT... 时立即生效,但我错了。实际上,当你按照上述方式进行操作时,当它到达BEGIN... 时,就会发生更新。

总结一下:

像这样进行更新:

UPDATE ProcActivity SET IsActive = 1 WHERE ProcedureName = 'proc_name'
BEGIN TRANSACTION
EXEC proc_name
COMMIT TRANSACTION
UPDATE ProcActivity SET IsActive = 0 WHERE ProcedureName = 'proc_name'

导致IsActive的值在过程proc_name执行期间被设置为1(更新在过程开始之前生效)。

像这样进行更新:

BEGIN TRANSACTION
UPDATE ProcActivity SET IsActive = 1 WHERE ProcedureName = 'proc_name'
COMMIT TRANSACTION
EXEC proc_name
UPDATE ProcActivity SET IsActive = 0 WHERE ProcedureName = 'proc_name'

在执行proc_name 期间将不起作用。 IsActive 的值在过程执行期间设置为 0。

为什么会这样?其背后的机制是什么?

【问题讨论】:

    标签: sql sql-server sql-update commit


    【解决方案1】:

    我无法重现您的问题 - 在这两种情况下,我都会得到 0 - 1 - 0

    IF OBJECT_ID('[dbo].[StackOoverFlow]') IS NOT NULL
    BEGIN
        DROP TABLE [dbo].[StackOoverFlow];
    END;
    
    IF OBJECT_ID('[dbo].[usp_StackOoverFlow]') IS NOT NULL
    BEGIN
        DROP PROCEDURE [dbo].[usp_StackOoverFlow];
    END;
    
    GO
    
    CREATE TABLE [dbo].[StackOoverFlow]
    (
        [ProcedureName] SYSNAME
       ,[IsActive] BIT
    ); 
    
    GO
    
    CREATE PROCEDURE [dbo].[usp_StackOoverFlow] AS
    BEGIN
        SELECT [IsActive]
        FROM [dbo].[StackOoverFlow]
        WHERE [ProcedureName] = '[dbo].[usp_StackOoverFlow]';
    END;
    
    GO
    
    INSERT INTO [dbo].[StackOoverFlow] ([ProcedureName], [IsActive])
    VALUES ('[dbo].[usp_StackOoverFlow]', 0);
    
    GO
    
    SELECT [IsActive]
    FROM [dbo].[StackOoverFlow]
    WHERE [ProcedureName] = '[dbo].[usp_StackOoverFlow]';
    
    BEGIN TRANSACTION
    
    UPDATE [dbo].[StackOoverFlow]
    SET [IsActive] = 1
    WHERE [ProcedureName] = '[dbo].[usp_StackOoverFlow]'; 
    
    COMMIT TRANSACTION
    
    EXEC [dbo].[usp_StackOoverFlow];
    
    UPDATE [dbo].[StackOoverFlow]
    SET [IsActive] = 0
    WHERE [ProcedureName] = '[dbo].[usp_StackOoverFlow]'; 
    
    SELECT [IsActive]
    FROM [dbo].[StackOoverFlow]
    WHERE [ProcedureName] = '[dbo].[usp_StackOoverFlow]';
    
    
    GO
    
    SELECT [IsActive]
    FROM [dbo].[StackOoverFlow]
    WHERE [ProcedureName] = '[dbo].[usp_StackOoverFlow]';
    
    UPDATE [dbo].[StackOoverFlow]
    SET [IsActive] = 1
    WHERE [ProcedureName] = '[dbo].[usp_StackOoverFlow]'; 
    
    BEGIN TRANSACTION
    EXEC [dbo].[usp_StackOoverFlow];
    COMMIT TRANSACTION
    
    UPDATE [dbo].[StackOoverFlow]
    SET [IsActive] = 0
    WHERE [ProcedureName] = '[dbo].[usp_StackOoverFlow]'; 
    
    SELECT [IsActive]
    FROM [dbo].[StackOoverFlow]
    WHERE [ProcedureName] = '[dbo].[usp_StackOoverFlow]';
    

    【讨论】:

    • 那么,两个代码的效果完全一样吗?所以第一个代码按我想的那样工作?
    • 您可以在您的 SQL Server 上试用此代码。在我的工作环境中也是如此。如果你的不一样,你可以先显示SP body。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-14
    • 1970-01-01
    相关资源
    最近更新 更多