Должны ли мы обрабатывать транзакции в коде 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
Ракеш Гаур
источник

Ответы:

20

Во-первых , у вас всегда должна быть правильная обработка транзакций во всех ваших процедурах, чтобы не имело значения, если они вызываются кодом приложения, другой процедурой, индивидуально в специальном запросе, заданием агента SQL или каким-либо другим способом. , Но отдельные операторы DML или код, который не вносит никаких изменений, не требуют явной транзакции. Итак, что я рекомендую это:

  • Всегда используйте структуру TRY / CATCH, чтобы ошибки можно было правильно всплыть
  • При желании включите 3 фрагмента обработки транзакций в код ниже, если у вас есть несколько операторов DML (поскольку один оператор сам по себе является транзакцией). ОДНАКО, кроме добавления некоторого дополнительного кода, где он специально не нужен, если кто-то предпочитает иметь непротиворечивый шаблон, тогда не помешает оставаться в 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;

Во-вторых , вам следует обрабатывать транзакцию на уровне приложения только в том случае, если вам нужно выполнить более 1 запроса / хранимой процедуры, и все они должны быть сгруппированы в элементарную операцию. Выполнение сингла SqlCommand.Execute___должно быть только в попытке / улове, но не в транзакции.

Но вредно ли выполнять транзакцию на уровне приложения, когда выполняется только один вызов? Если для этого требуется MSDTC (координатор распределенных транзакций Microsoft), то в системе немного сложнее сделать это на уровне приложения, если в этом нет явной необходимости. Лично я предпочитаю избегать транзакций на уровне приложения, за исключением случаев, когда это абсолютно необходимо, поскольку это снижает вероятность потерянных транзакций (если что-то пошло не так с кодом приложения перед выполнением фиксации или отката). Я также обнаружил, что это иногда затрудняет отладку определенных ситуаций. Но это , как говорится, я не вижу ничего технически неправильно с также обработки транзакции в приложении слоя при создании единого проквызов; опять же, один оператор DML является собственной транзакцией и не требует какой-либо явной обработки транзакций на любом уровне.

Соломон Руцкий
источник