【问题标题】:Is it necessary to use a transaction if other statements are dependent on the first?如果其他语句依赖于第一个语句,是否有必要使用事务?
【发布时间】:2015-03-16 21:41:56
【问题描述】:

长期以来,我一直忽略使用 SQL 事务,主要是出于无知。

但是假设我有一个这样的程序:

CREATE PROCEDURE CreatePerson

AS
BEGIN

declare @NewPerson INT

INSERT INTO PersonTable ( Columns... ) VALUES ( @Parameters... )
SET @NewPerson = SCOPE_IDENTITY()

INSERT INTO AnotherTable ( @PersonID, CreatedOn ) VALUES ( @NewPerson, getdate() )

END
GO

在上面的示例中,第二个插入依赖于第一个,因为如果第一个失败,它将失败。

其次,无论出于何种原因,就正确实施而言,交易让我感到困惑。我在这里看到了一个例子,在那儿看到了另一个例子,我刚刚打开了 Adventureworks 以找到另一个示例,包括 try、catch、rollback 等。

我没有记录错误。我应该在这里使用交易吗?这值得么?

如果是这样,应该如何正确实施?根据我看到的例子:

CREATE PROCEURE CreatePerson

AS
BEGIN TRANSACTION

....

COMMIT TRANSACTION
GO

或者:

CREATE PROCEDURE CreatePerson

AS
BEGIN
    BEGIN TRANSACTION

    COMMIT TRANSACTION
END
GO

或者:

CREATE PROCEDURE CreatePerson

AS
BEGIN

BEGIN TRY
    BEGIN TRANSACTION

    ...

    COMMIT TRANSACTION
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0
    BEGIN
        ROLLBACK TRANSACTION
    END
END CATCH
END

最后,在我的真实代码中,我有更多的 5 个单独的插入,全部基于新生成的人员 ID。如果你是我,你会怎么做?这个问题可能是多余的或重复的,但无论出于何种原因,我似乎无法在脑海中调和处理这个问题的最佳方法。

另一个令人困惑的领域是回滚。如果必须将事务作为单个操作单元提交,如果不使用回滚会发生什么?还是只有在类似于 vb.net/c# 错误处理的 Try/Catch 中才需要回滚?

【问题讨论】:

    标签: sql-server transactions sql-server-2012


    【解决方案1】:

    您可能错过了这一点:假设事务将一组单独的操作合二为一,因此如果一个操作失败,您可以回滚并且您的数据库将保持不变,就好像什么都没发生一样。

    这更容易查看,例如,您是否将购买的详细信息保存在商店中。您保存了客户的数据(如姓名或地址),但不知何故,您错过了详细信息(服务器崩溃)。所以现在你知道 John Doe 买了东西,但你不知道是什么。您数据完整性处于危险之中。

    如果您想在 SP 中处理事务,您的第三个示例代码是正确的。要返回错误,您可以尝试:

    RETURN @@ERROR
    

    回滚之后。另外,请查看:

    set xact_abort on
    

    如:SQL Server - transactions roll back on error?

    【讨论】:

    • 经过一番研究后,我认为我更赞成 xact_abort ... 如果确实不需要特定的错误处理,似乎更容易处理。
    • 如果我要使用 xact_abort,看看我的第一个和第二个例子...第一个就足够了吗? BEGIN 然后 BEGIN TRANS 有什么好处吗?还是当你有多个交易块的时候?
    • 第一个 BEGIN 是存储过程的开始。 BEGIN TRANS 用于事务的开始。我建议您这样做以保持井井有条。此外,xact_abort on 将在其中任何一个中以相同的方式工作,问题是这不会捕获所有可能的错误,因此您最好使用 TRY CATCH。
    【解决方案2】:

    如果第一次插入成功而第二次失败,您的数据库将处于错误状态,因为 SQL Server 无法读懂您的想法。即使您可能希望它全部成功或全部失败,它也会将第一个插入(更改)留在数据库中。

    为确保这一点,您应该按照上一个示例中的说明将所有语句包装在 begin transaction 中。捕获很重要,这样任何半完成的事务都会显式回滚,并尽快释放资源(由事务使用)。

    【讨论】:

    • 在这种情况下,try/catch 效果如何将错误输出参数返回给客户端?都一样吗?
    • 一旦你输入了catch,你就可以保留错误设置的值。您可以使用 raiseerror 重新引发错误。有关此示例,请参阅:sqlblog.com/blogs/roman_rehak/archive/2007/12/01/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-02-17
    • 1970-01-01
    • 2021-08-04
    • 1970-01-01
    • 2017-03-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多