Sommes-nous tenus de gérer la transaction en code C # ainsi qu'en procédure stockée

14

Avons-nous vraiment besoin de la gestion des transactions en c # ainsi que du processus de stockage de base de données des deux côtés

C #:

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

Procédure stockée SQL:

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

Réponses:

20

Tout d'abord , vous devez toujours avoir une gestion des transactions appropriée dans toutes vos procédures afin que peu importe qu'elles soient appelées par le code d'application, par une autre procédure, individuellement dans une requête ad hoc, par un travail de l'Agent SQL ou par tout autre moyen . Mais les instructions DML simples ou le code qui n'apporte aucune modification n'ont pas besoin d' une transaction explicite. Donc, ce que je recommande, c'est:

  • Ayez toujours la structure TRY / CATCH pour que les erreurs puissent être propulsées correctement
  • Incluez éventuellement les 3 éléments de gestion des transactions dans le code ci-dessous si vous avez plusieurs instructions DML (car une seule instruction est une transaction en soi). CEPENDANT, en dehors de l'ajout de code supplémentaire là où il n'est pas spécifiquement nécessaire, si l'on préfère avoir un modèle cohérent, cela ne fait pas de mal de conserver les 3 blocs IF liés à la transaction. Mais dans ce cas, je recommanderais toujours de ne pas conserver les 3 blocs IF liés aux transactions pour les processus SELECT uniquement (c'est-à-dire en lecture seule).

Lorsque vous effectuez 2 instructions DML ou plus, vous devez utiliser quelque chose dans le sens de ce qui suit (ce qui peut également être fait pour des opérations DML simples si l'on préfère être cohérent):

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;

Lorsque vous effectuez une seule instruction DML ou simplement un SELECT, vous pouvez vous en sortir avec les éléments suivants:

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;

Deuxièmement , vous devez gérer la transaction au niveau de la couche d'application uniquement si vous devez exécuter plus d'une requête / procédure stockée et qu'elles doivent toutes être regroupées en une opération atomique. Faire un single SqlCommand.Execute___doit seulement être dans un try / catch, mais pas dans une transaction.

Mais, est-ce que cela fait mal de faire une transaction au niveau de la couche d'application lors d'un seul appel? S'il nécessite MSDTC (Microsoft Distributed Transaction Coordinator), il est un peu plus lourd sur le système de le faire au niveau de l'application lorsque cela n'est pas expressément nécessaire. Personnellement, je préfère éviter les transactions basées sur la couche d'application, sauf si cela est absolument nécessaire, car cela réduit le potentiel de transactions orphelines (si quelque chose s'est mal passé avec le code de l'application avant de faire la validation ou la restauration). J'ai également constaté que cela rend parfois le débogage de certaines situations un peu plus difficile. Mais cela étant dit, je ne vois rien de mal techniquement à gérer également la transaction au niveau de la couche d'application lors de la création d'un seul processus.appel; encore une fois, une seule instruction DML est sa propre transaction et ne nécessite aucune gestion de transaction explicite sur l'une ou l'autre couche.

Solomon Rutzky
la source