Somos obrigados a lidar com a transação no código C #, bem como no procedimento armazenado

14

Nós realmente exigimos manipulação de transações em c #, bem como o processo de armazenamento de banco de dados nos dois lados

C #:

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

Procedimento armazenado SQL:

Create process
As
Begin try
    Begin transaction
    Commit
End try
Begin catch
    Rollback
End catch
Rakesh Gaur
fonte

Respostas:

20

Primeiro , você deve sempre ter manipulação de transação adequada em todos os seus procedimentos, para que não importem se eles são chamados pelo código do aplicativo, por outro procedimento, individualmente em uma consulta ad-hoc, por um trabalho do SQL Agent ou por outros meios. . Mas instruções DML únicas, ou código que não faz modificações, não precisam de uma transação explícita. Então, o que eu estou recomendando é:

  • Sempre tenha a estrutura TRY / CATCH para que os erros possam ser corretamente identificados
  • Opcionalmente, inclua as 3 partes de manipulação de transações no código abaixo se você tiver várias instruções DML (uma vez que uma única instrução é uma transação em si). NO ENTANTO, além de adicionar algum código adicional onde não é especificamente necessário, se alguém preferir ter um modelo consistente, não faz mal manter os 3 blocos IF relacionados à transação. Mas, nesse caso, eu ainda recomendaria não manter os 3 blocos IF relacionados à transação para procs SELECT-only (ou seja, somente leitura).

Ao executar 2 ou mais instruções DML, você precisa usar algo como as seguintes (o que também pode ser feito para operações DML únicas, se preferir ser consistente):

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;

Ao fazer apenas uma instrução DML ou apenas um SELECT, você pode se safar do seguinte:

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;

Segundo , você deve manipular a transação na camada de aplicativo apenas se precisar executar mais de 1 procedimento armazenado / consulta e todos eles precisarem ser agrupados em uma operação atômica. Fazer um único SqlCommand.Execute___precisa estar apenas em uma tentativa / captura, mas não em uma Transação.

Mas, dói fazer uma transação na camada de aplicativo ao fazer apenas uma única chamada? Se exigir o MSDTC (Coordenador de transações distribuídas da Microsoft), o sistema será um pouco mais pesado para fazer isso na camada de aplicativos quando não for expressamente necessário. Pessoalmente, prefiro evitar transações baseadas na camada de aplicativos, a menos que seja absolutamente necessário, pois reduz o potencial de transações órfãs (se algo der errado com o código do aplicativo antes de confirmar ou reverter). Também descobri que algumas vezes torna a depuração de certas situações um pouco mais difícil. Mas o que foi dito, eu não vejo nada tecnicamente errado com também tratamento da operação na camada de aplicativo ao fazer um único procligar; novamente, uma única instrução DML é sua própria transação e não precisa de nenhuma manipulação explícita de transação em qualquer camada.

Solomon Rutzky
fonte