我们是否需要使用C#代码以及存储过程来处理事务


14

我们是否真的需要c#中的事务处理以及数据库存储过程双方

C#:

Using(transaction with transaction scope)
{
     Execute stored proc;
     Transaction. Complete;
}

SQL存储过程:

Create process
As
Begin try
    Begin transaction
    Commit
End try
Begin catch
    Rollback
End catch

Answers:


20

首先,您应该在所有过程中始终进行适当的事务处理,以便由应用程序代码,其他过程,在临时查询中单独进行,由SQL Agent作业或其他方式调用它们都无所谓。但是,单个DML语句或未进行任何修改的代码不需要显式的Transaction。所以,我推荐的是:

  • 始终具有TRY / CATCH结构,以便可以正确冒起错误
  • 如果您有多个DML语句,则可以选择在下面的代码中包含3个事务处理部分(因为单个语句本身就是事务)。但是,除了在不需要的地方添加一些其他代码之外,如果您希望有一个一致的模板,那么保留在3个与事务相关的IF块中也没有什么害处。但是在那种情况下,我仍然建议不要将3个与事务相关的IF块保留给SELECT(仅只读)处理。

当执行2条或更多条DML语句时,您需要按照以下方式使用某些内容(如果希望保持一致,也可以对单个DML操作执行此操作):

CREATE PROCEDURE [SchemaName].[ProcedureName]
(
    @Param  DataType
    ...
)
AS
SET NOCOUNT ON;
DECLARE @InNestedTransaction BIT;

BEGIN TRY

    IF (@@TRANCOUNT = 0)
    BEGIN
        SET @InNestedTransaction = 0;
        BEGIN TRAN; -- only start a transaction if not already in one
    END;
    ELSE
    BEGIN
        SET @InNestedTransaction = 1;
    END;

    -- { 2 or more DML statements (i.e. INSERT / UPDATE / DELETE) }

    IF (@@TRANCOUNT > 0 AND @InNestedTransaction = 0)
    BEGIN
        COMMIT;
    END;

END TRY
BEGIN CATCH

    IF (@@TRANCOUNT > 0 AND @InNestedTransaction = 0)
    BEGIN
        ROLLBACK;
    END;

    DECLARE @ErrorMessage   NVARCHAR(4000) = ERROR_MESSAGE(),
            @ErrorState     INT = ERROR_STATE(),
            @ErrorSeverity  INT = ERROR_SEVERITY();

    -- optionally concatenate ERROR_NUMBER() and/or ERROR_LINE() into @ErrorMessage

    RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState);
    RETURN;

END CATCH;

当仅执行1个DML语句或仅执行SELECT时,您可以仅执行以下操作:

CREATE PROCEDURE [SchemaName].[ProcedureName]
(
    @Param  DataType
    ...
)
AS
SET NOCOUNT ON;

BEGIN TRY

    -- { 0 or 1 DML statements (i.e. INSERT / UPDATE / DELETE) }

END TRY
BEGIN CATCH

    DECLARE @ErrorMessage   NVARCHAR(4000) = ERROR_MESSAGE(),
            @ErrorState     INT = ERROR_STATE(),
            @ErrorSeverity  INT = ERROR_SEVERITY();

    -- optionally concatenate ERROR_NUMBER() and/or ERROR_LINE() into @ErrorMessage

    RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState);
    RETURN;

END CATCH;

其次当您需要执行多个查询/存储过程并且都需要将它们全部分组为一个原子操作时,才应在应用程序层处理事务。做一个SqlCommand.Execute___只需要在一个try / catch,而不是在交易中。

但是,仅拨打一个电话时,在应用程序层进行事务处理是否有害?如果它需要MSDTC(Microsoft分布式事务处理协调器),那么在系统上,如果没有特别需要,则可以在应用程序层执行此操作,这会比较重。我个人更喜欢避免基于应用程序层的事务,除非绝对必要,因为这样可以减少孤立事务的可能性(如果在提交或回滚之前应用程序代码出现问题)。我还发现,有时使调试某些情况变得有些困难。话虽这么说,我在进行单个proc时在应用程序层处理事务没有任何技术上的错误呼叫; 再次,一个DML语句是它自己的事务,并不需要任何明确的事务在任层处理。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.