IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Développement SQL Server Discussion :

Gestion de @@trancount dans les procédures stockées


Sujet :

Développement SQL Server

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Futur Membre du Club
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Octobre 2022
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Chef de projet en SSII

    Informations forums :
    Inscription : Octobre 2022
    Messages : 5
    Par défaut Gestion de @@trancount dans les procédures stockées
    Bonjour à tous
    Dans mon code, j'utilise beaucoup les procédures stockées imbriquées. Les traitements de mes procédures stockées effectuent tous plusieurs opérations dans la base de données, ils sont donc encapsulés dans une transaction. Mes procédures stockées enfants peuvent être également éxécutées en tant que parent. Je démarre donc toutes mes procédures stockées enfant par un BEGIN TRAN après le BEGIN TRY et en cas d'erreur, je teste la condition suivante avant d'effectuer un rollback : IF @@trancount = 1 and xact_state()<>0. Ma question est la suivante, lorsque j'effectue un EXECUTE d'une procédure stockée, est ce que la valeur de @@trancount peut être modifiée par un autre EXECUTE d'une procédure stockée, hors appels de procédure stockée interne ou externe.
    Exemple :
    la procédure stockée A appelle la procédure stockée B
    la procédure stockée C ne fait appel à aucune autre procédure stockée
    Le traitement de chacune des procédures stockées est encapsulé dans une transaction

    Est ce que, dans la même session user, le cas présent peut se produire :
    J'éxécute la procédure stockée A, la valeur de @@trancount passe à 1 puis à 2 après le BEGIN TRAN de la procédure stockée B
    Maintenant, imaginons que ma procédure ne soit pas terminée mais que, dans le même temps, le moteur SQL Server éxecute la procédure stockée C sur la même session. Est ce que la valeur de @@trancount après le BEGIN TRAN de la procédure stockée est C est 1 ou 3 ?

  2. #2
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    22 010
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 22 010
    Billets dans le blog
    6
    Par défaut
    L'utilisation de @@TRANCOUNT n'est pas conseillé car complexe et piègeuse.

    Le bon squelette de code à adopter pour TOUTES vos procédures transactionnée est le suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    CREATE PROCEDURE ...
    AS
     
    ...
     
    BEGIN TRY
     
       ...
     
       BEGIN TRANSACTION;
     
       ...
     
       COMMIT;
     
       ...
     
    END TRY
    BEGIN CATCH
       IF XACT_STATE() <> 0
          ROLLBACK;
       THROW;
    END TRY
     
    ...
     
    GO
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

  3. #3
    Futur Membre du Club
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Octobre 2022
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Chef de projet en SSII

    Informations forums :
    Inscription : Octobre 2022
    Messages : 5
    Par défaut
    Merci beaucoup pour votre réponse @sqlpro, c'est exactement ce que j'avais écrit.
    Sauf que : j'ai décidé d'ajouter un insert de l'erreur rencontrée après le rollback pour pouvoir journaliser les erreurs. Et pour aérer au maximum le code, je me suis dit que je vais gérer tout ça dans une autre procédure stockée, ce qui me donne
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
     
     
    --procédure handle error
    PROCEDURE sp_i_ts_erreur_err
    AS
    BEGIN
    	SET NOCOUNT, XACT_ABORT ON;
     
    	BEGIN TRY		
                    IF XACT_STATE()<>0
                        ROLLBACK
     
    		DECLARE @v_erreur_numero int = ERROR_NUMBER()
    		,@v_erreur_severite int = ERROR_SEVERITY()
    		,@v_erreur_etat int = ERROR_STATE()
    		,@v_erreur_procedure nvarchar(126) = ERROR_PROCEDURE()
    		,@v_erreur_ligne int = ERROR_LINE()
    		,@v_erreur_message nvarchar(2048) = ERROR_MESSAGE()
    		,@v_date datetime2(0) = getdate()
    		,@v_user nvarchar(128) = system_user;
     
     
    		EXEC sp_executesql N'INSERT INTO ts_erreur_err(err_user,err_date,err_numero,err_etat,err_severite,err_ligne,err_procedure,err_message) VALUES (@user,@date,@numero,@etat,@severite,@ligne,@procedure,@message) 
    		',N'@user nvarchar(128),@date datetime2(0),@numero int,@etat int,@severite int,@ligne int,@procedure nvarchar(128),@message 
                     nvarchar(2048)',@v_user,@v_date,@v_erreur_numero,@v_erreur_etat,@v_erreur_severite,@v_erreur_ligne,@v_erreur_procedure,@v_erreur_message
     
    	END TRY
     
    	BEGIN CATCH
    		;THROW
        END CATCH
    END
     
    -- procédure modèle
    CREATE PROCEDURE ...
    AS
     
    ...
     
    BEGIN TRY
     
       ...
     
       BEGIN TRANSACTION;
     
       ...
     
       COMMIT;
     
       ...
     
    END TRY
    BEGIN CATCH
       execute sp_i_ts_erreur_err
       ;THROW
    END TRY
    Lorsque j'exécute ce code, l'erreur n°266 m'est retourné. Elle m'indique que le nombre de transactions après EXECUTE indique un nombre différent d'instructions BEGIN et COMMIT.
    Cette erreur n'est pas bloquante mais je ne comprends pas pourquoi elle m'est retourné dans ce cas de figure et pourquoi cela n'est pas le cas lorsque je modifie mon code comme ci-dessous

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
     
     
    --procédure handle error
    PROCEDURE sp_i_ts_erreur_err
    AS
    BEGIN
    	SET NOCOUNT, XACT_ABORT ON;
     
    	BEGIN TRY		
     
    		DECLARE @v_erreur_numero int = ERROR_NUMBER()
    		,@v_erreur_severite int = ERROR_SEVERITY()
    		,@v_erreur_etat int = ERROR_STATE()
    		,@v_erreur_procedure nvarchar(126) = ERROR_PROCEDURE()
    		,@v_erreur_ligne int = ERROR_LINE()
    		,@v_erreur_message nvarchar(2048) = ERROR_MESSAGE()
    		,@v_date datetime2(0) = getdate()
    		,@v_user nvarchar(128) = system_user;
     
     
    		EXEC sp_executesql N'INSERT INTO ts_erreur_err(err_user,err_date,err_numero,err_etat,err_severite,err_ligne,err_procedure,err_message) VALUES (@user,@date,@numero,@etat,@severite,@ligne,@procedure,@message) 
    		',N'@user nvarchar(128),@date datetime2(0),@numero int,@etat int,@severite int,@ligne int,@procedure nvarchar(128),@message 
                     nvarchar(2048)',@v_user,@v_date,@v_erreur_numero,@v_erreur_etat,@v_erreur_severite,@v_erreur_ligne,@v_erreur_procedure,@v_erreur_message
     
    	END TRY
     
    	BEGIN CATCH
    		;THROW
        END CATCH
    END
     
    -- procédure modèle
    CREATE PROCEDURE ...
    AS
     
    ...
     
    BEGIN TRY
     
       ...
     
       BEGIN TRANSACTION;
     
       ...
     
       COMMIT;
     
       ...
     
    END TRY
    BEGIN CATCH
            IF XACT_STATE()<>0
            BEGIN
                ROLLBACK
                execute sp_i_ts_erreur_err
            END
            ;THROW
    END TRY
    Pouvez vous éclairer mon ignorance ???

  4. #4
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    22 010
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 22 010
    Billets dans le blog
    6
    Par défaut
    Tout simplement parce que tu ouvre une nouvelle transaction pour gérer l'insertion de ton erreur dans une table...

    Il ne faut pas gérer de transaction dans ce cas de figure, mais transmettre les informations à stocker via une variable table qui n'est pas concernée par les opérations de ROLLBACK ou COMMIT, puisque c'est une variable et non une table.

    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

  5. #5
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    22 010
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 22 010
    Billets dans le blog
    6
    Par défaut
    Tu peux aussi utiliser une variable XML pour synthétiser l'erreur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    DECLARE @XML_ERROR XML = CAST((
    SELECT ERROR_NUMBER() AS ERROR_NUMBER,
           ERROR_SEVERITY() AS ERROR_SEVERITY,
    	   ERROR_STATE() AS ERROR_STATE,
    	   ERROR_PROCEDURE() AS ERROR_PROCEDURE,
    	   ERROR_LINE() AS ERROR_LINE,
    	   ERROR_MESSAGE() AS ERROR_MESSAGE,
    	   SYSUTCDATETIME() AS UTC_DH,
    	   SYSDATETIME() AS LOCAL_DH,
    	   system_user AS "LOGIN",
    	   USER AS "USER",
    	   ORIGINAL_LOGIN() AS ORIGINAL_LOGIN,
    	   ORIGINAL_DB_NAME() AS ORIGINAL_DB_NAME,
    	   DB_NAME() AS CONTEXTUAL_DB_NAME,
    	   PROGRAM_NAME() AS PROGRAM_NAME,
    	   HOST_NAME() AS HOST_NAME,
    	   (SELECT client_net_address FROM sys.dm_exec_connections WHERE session_id = @@SPID)
    FOR XML AUTO, ELEMENTS, ROOT('error')) AS XML);
    Puis transmettre à une proc hyper simple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    CREATE PROC P_STACK_ERROR @XML XML
    AS
    SE NOCOUNT ON;
    INSERT INTO S_ERROR.T_TRACK_ERROR VALUES (@XML);
    GO
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

  6. #6
    Futur Membre du Club
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Octobre 2022
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Chef de projet en SSII

    Informations forums :
    Inscription : Octobre 2022
    Messages : 5
    Par défaut
    Merci pour votre réponse SQLPro
    Néanmoins quelque chose m'échappe...
    Ma procédure stockée qui capte l'erreur et fait le rollback ne déclenche pas de transaction explicite alors je suppose que vous parlez de transaction implicite déclenchée par l'insert... Cependant si je fais un test en supprimant la commande insert de ma procédure stockée et en conservant uniquement le rollback, le message d'erreur 266 se déclenche quand même... ???
    J'ai lu que l'erreur 266 se déclenche lorsque vous quittez une procédure stockée et que @@trancount a une valeur différente de celle du début de l'exécution de la procédure. Or, dans le cas de procédures stockées imbriquées, en cas d'erreur dans une procédure stockée "enfant", je vais toujours retomber dans ce cas de figure si j'effectue le rollback dans la procédure stockée "enfant". Pour ne pas avoir cette erreur, il faudrait que j'effectue le rollback uniquement dans la procédure stockée parent même si l'erreur se produit dans l'enfant...
    Je n'ai pas vraiment envie d'adopter ce dernier modèle. Etant donné que l'erreur 266 n'est pas une erreur bloquante, pensez-vous que je puisse l'ignorer ?

Discussions similaires

  1. Les transactions dans les procédures stockées
    Par CharleLéo dans le forum Connexion aux bases de données
    Réponses: 2
    Dernier message: 04/12/2009, 16h04
  2. recherche texte dans les procédures stockée
    Par battl14 dans le forum MS SQL Server
    Réponses: 1
    Dernier message: 27/03/2009, 14h02
  3. Arguments dans les procédures stockées
    Par sliderman dans le forum PostgreSQL
    Réponses: 3
    Dernier message: 28/03/2008, 13h29
  4. Réponses: 3
    Dernier message: 03/08/2007, 21h11
  5. Gestion d'erreur dans les procédure
    Par speedy1496 dans le forum MS SQL Server
    Réponses: 5
    Dernier message: 20/01/2006, 12h02

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo