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 :

PB de ROLLBACK dans un trigger, pb niveau de transaction


Sujet :

Développement SQL Server

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    616
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Luxembourg

    Informations forums :
    Inscription : Mars 2007
    Messages : 616
    Par défaut PB de ROLLBACK dans un trigger, pb niveau de transaction
    Bonjour,

    J'ai un pb avec un tout petit trigger.
    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
     
    create table A (
       C1             int                  not null,
       C2             int                  not null,
       C3             varchar(20)          null,
       constraint PK_A primary key  (C1, C2)
    )
    GO
     
    CREATE TRIGGER TR_a
    ON A
    FOR INSERT, UPDATE, DELETE
    AS
    	PRINT '@@TRANCOUNT = ' + CONVERT(VARCHAR, @@TRANCOUNT)
    	if exists(select * from deleted)
    	BEGIN
    		raiserror('no delete',16,1)
    		ROLLBACK TRAN
    	END
     
    	PRINT '@@TRANCOUNT = ' + CONVERT(VARCHAR, @@TRANCOUNT)
    	print 'TABLE A'
    	SELECT * from A
     
    	print 'inserted'
    	select * from Inserted
     
    	print 'deleted'
    	select * from Deleted
    GO
     
     
    INSERT INTO A
    VALUES(1,4,'123')
     
    PRINT '@@TRANCOUNT = ' + CONVERT(VARCHAR, @@TRANCOUNT)
     
    BEGIN TRAN TRA	-- début de transaction
     
    PRINT '@@TRANCOUNT = ' + CONVERT(VARCHAR, @@TRANCOUNT)
    DELETE FROM A
    PRINT '@@TRANCOUNT = ' + CONVERT(VARCHAR, @@TRANCOUNT)
     
    COMMIT TRAN TRA	-- problème
    Mon trigger veut empêcher les delete sur ma table.
    Le pb est que le ROLLBACK pose un problème pour ma transaction TRA qui essaie d'effacer ma table.

    L'instruction de COMMIT TRAN TRA provoque une erreur, car la transaction est déjà rollbackée par le trigger.


    Comment est ce que je peux faire:
    - soit executer le trigger AVANT l'instruction?
    - soit faire un ROLLBACK dans le trigger mais sans impacter sur la transaction TRA?

  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
    21 998
    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 : 21 998
    Billets dans le blog
    6
    Par défaut
    Vous êtes contradictoire :

    Mon trigger veut empêcher les delete sur ma table.
    ma transaction TRA qui essaie d'effacer ma table.
    Que voulez vous faire : empecher le delete ou le faire ???

    De plus si vous voulez faire des transaction imbriquées, il faut mettre en place un stratégie asymétrique. Lisez l'article que j'ai écrit à ce sujet :
    http://sqlpro.developpez.com/cours/s...ns-imbriquees/

    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/ * * * * *

  3. #3
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    616
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Luxembourg

    Informations forums :
    Inscription : Mars 2007
    Messages : 616
    Par défaut
    Citation Envoyé par SQLpro Voir le message
    Vous êtes contradictoire :

    Que voulez vous faire : empecher le delete ou le faire ???

    De plus si vous voulez faire des transaction imbriquées, il faut mettre en place un stratégie asymétrique. Lisez l'article que j'ai écrit à ce sujet :
    http://sqlpro.developpez.com/cours/s...ns-imbriquees/

    A +
    Je veux le faire de façon conditionnelle, par le trigger. J'ai pas mis la condition, juste pour simplifier le code.

    j'ai lu l'article, je ne comprends pas à quoi sert
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    IF @@ROWCOUNT = 1
       ROLLBACK TRANSACTION
    d'où viendra @@ROWCOUNT = 1?

  4. #4
    Modérateur

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Janvier 2005
    Messages
    5 826
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2005
    Messages : 5 826
    Par défaut
    Bonjour,

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    IF EXISTS(SELECT * FROM deleted)
    	BEGIN
    		raiserror('no delete',16,1)
    		ROLLBACK TRAN
    	END
    Vous ne pouvez pas défaire la transaction ou une partie de celle-ci puis la valider ensuite.
    Le mécanisme des transactions fonctionne suivant le tout ou rien :
    - toute la transaction est réussie, donc elle est validée
    - une partie de la transaction échoue, donc toute la transaction est défaite.

    Cela permet de conserver dans un état consistant et cohérent une base de données.

    - soit executer le trigger AVANT l'instruction?
    Il est impossible sous SQL Server d'exécuter un trigger avant la transaction, en revanche vous pouvez spécifier un trigger INSTEAD OF

    d'où viendra @@ROWCOUNT = 1?
    Du nombre de lignes affectées dans la table par votre instruction DELETE

    @++

  5. #5
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    616
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Luxembourg

    Informations forums :
    Inscription : Mars 2007
    Messages : 616
    Par défaut
    Citation Envoyé par elsuket Voir le message
    Bonjour,


    Vous ne pouvez pas défaire la transaction ou une partie de celle-ci puis la valider ensuite.
    Le mécanisme des transactions fonctionne suivant le tout ou rien :
    - toute la transaction est réussie, donc elle est validée
    - une partie de la transaction échoue, donc toute la transaction est défaite.

    Cela permet de conserver dans un état consistant et cohérent une base de données.
    Oui, je sais. J'ai pris ce code, car j'au vu beaucoup d'exemples de triggers ou on fait
    RAISEROR(..) puis
    ROLLBACK TRAN
    Le pb c'est que ça annule toute la transaction et non l'instruction qui a fait déclencher le trigger.
    Il est impossible sous SQL Server d'exécuter un trigger avant la transaction, en revanche vous pouvez spécifier un trigger INSTEAD OF
    Ca c'est nul par contre, je sais que sous Oracle, ça existe.
    Je crois que je vais devoir passer par INSTED OF et ça m'énerve un peu.

    Du nombre de lignes affectées dans la table par votre instruction DELETE
    @++
    En faite ça viens de l'article de SQLPro
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    -- partie à rajouter à TOUTES les procédures (finalisation) :
     
    -- succès
    COMMIT TRANSACTION
    RETURN (0)
     
    -- échec
    LBL_ERROR:
    IF @@TRANCOUNT > 1
       COMMIT TRANSACTION
    IF @@ROWCOUNT = 1
       ROLLBACK TRANSACTION
    RETURN (-1)
    Et c'est là que je ne comprends pas pourquoi @@ROWCOUNT = 1?

  6. #6
    Modérateur

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Janvier 2005
    Messages
    5 826
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2005
    Messages : 5 826
    Par défaut
    Ca c'est nul par contre, je sais que sous Oracle, ça existe.
    Effectivement ça existe sous Oracle, mais plus vous écrirez de triggers sous SQL Server, et plus vous vous rendez compte que ça ne sert pas à grand chose ...

    Le pb c'est que ça annule toute la transaction et non l'instruction qui a fait déclencher le trigger.
    Sous SQL Server, toute instruction est une transaction.

    Je crois que je vais devoir passer par INSTED OF et ça m'énerve un peu.
    Pourquoi ?

    @++

Discussions similaires

  1. Réponses: 3
    Dernier message: 15/06/2006, 15h58
  2. Recuperer derniere valeur modifiée dans un trigger
    Par xabs dans le forum Développement
    Réponses: 2
    Dernier message: 06/08/2004, 16h22
  3. RAZ GENERATOR dans un trigger
    Par kase74 dans le forum SQL
    Réponses: 2
    Dernier message: 08/09/2003, 18h43
  4. select dans un trigger sous Postgresql
    Par kastor_grog dans le forum Requêtes
    Réponses: 1
    Dernier message: 03/09/2003, 17h00
  5. [PostgreSQL] Refus de STATEMENT dans un trigger
    Par alex2205 dans le forum Requêtes
    Réponses: 3
    Dernier message: 10/03/2003, 12h51

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