2009-09-11 4 views
15

mise à jour Disons que j'ai un déclencheur comme ceci:T-SQL: Une bonne façon de fermer/curseur DEALLOCATE dans la gâchette

CREATE TRIGGER trigger1 
    ON [dbo].[table1] 
    AFTER UPDATE 
AS 
BEGIN    
    --declare some vars 
    DECLARE @Col1 SMALLINT 
    DECLARE @Col1 TINYINT 

    --declare cursor   
    DECLARE Cursor1 CURSOR FOR 
    SELECT Col1, Col2 FROM INSERTED    

    --do the job 
    OPEN Cursor1 
    FETCH NEXT FROM Cursor1 INTO @Col1, @Col2 

    WHILE @@FETCH_STATUS = 0 
    BEGIN 
     IF ...something... 
     BEGIN   
      EXEC myProc1 @param1 = @Col1, @Param2 = @Col2 
     END    
     ELSE 
     IF ...something else... 
     BEGIN   
      EXEC myProc2 @param1 = @Col1, @Param2 = @Col2 
     END  

     FETCH NEXT FROM Cursor1 INTO @Col1, @Col2    
    END 

    --clean it up  
    CLOSE Cursor1 
    DEALLOCATE Cursor1     
END 

Je veux être sûr que Cursor1 est toujours fermé et désalloué. Même myProc1 ou myProc2 échoue. Dois-je utiliser try/catch block?

+0

[Lecture obligatoire] (http://www.sommarskog.se/error-handling-I.html). –

Répondre

15

Oui, utilisez TRY/CATCH mais assurez-vous de libérer, etc. Malheureusement, il n'y a pas enfin dans SQL Server.

Cependant, je suggère enroulant cela dans un autre try/catch

CREATE TRIGGER trigger1 ON [dbo].[table1] AFTER UPDATE 
AS 
BEGIN       
    --declare some vars 
    DECLARE @Col1 SMALLINT, @Col1 TINYINT 

    BEGIN TRY 
     --declare cursor    
     DECLARE Cursor1 CURSOR FOR 
     SELECT Col1, Col2 FROM INSERTED      

     --do the job 
     OPEN Cursor1 
     FETCH NEXT FROM Cursor1 INTO @Col1, @Col2 

     WHILE @@FETCH_STATUS = 0 
     BEGIN 
      IF ...something... 
        EXEC myProc1 @param1 = @Col1, @Param2 = @Col2 
      ELSE 
      IF ...something else... 
        EXEC myProc2 @param1 = @Col1, @Param2 = @Col2 

      FETCH NEXT FROM Cursor1 INTO @Col1, @Col2        
     END 
    END TRY 
    BEGIN CATCH 
     --do what you have to 
    END CATCH 

    BEGIN TRY 
     --clean it up    
     CLOSE Cursor1 
     DEALLOCATE Cursor1         
    END TRY 
    BEGIN CATCH 
     --do nothing 
    END CATCH 
END 

Que ce soit un curseur dans un déclencheur est une bonne idée est une autre affaire ...

+0

Quel est votre raisonnement pour envelopper le nettoyage du curseur dans un bloc try/catch lorsque la capture ne fait rien? –

+4

@NickDeVore: parce que le curseur est peut-être déjà fermé, en fonction de l'échec de proc1 ou proc2 (dans un trigger, peut-être try/catch etc). Mieux vaut prévenir que guérir. – gbn

+0

Pouvez-vous utiliser la syntaxe TRY/CATCH dans le déclencheur? Ce que je sais, c'est que lorsqu'une erreur se produit dans un déclencheur, la transaction entière échoue, qu'il y ait try/catch ou non. –

1

Ce que vous devez faire est de ne jamais utiliser un curseur dans un déclencheur. Écrivez le bon code basé sur l'ensemble à la place. Si quelqu'un faisait une importation de données dans votre table de 100 000 nouveaux enregistrements, vous verrouiller la table pendant des heures et mettre votre base de données à un arrêt cinglant. C'est une très mauvaise pratique d'utiliser un curseur dans un déclencheur.

+1

Si quelqu'un importait des données dans cette table de 100 000 nouveaux enregistrements, cela ne bloquerait pas du tout ma table (parce que c'est un déclencheur après la mise à jour;) Mais sérieusement. Ne vous méprenez pas. Je comprends parfaitement ce que vous voulez dire et vous avez raison. Je n'utiliserais jamais un curseur dans un trigger sauf si cela est absolument nécessaire et dans mon cas c'est le cas. En théorie, seules quelques lignes peuvent être mises à jour en même temps à partir de mon application (sauf si quelqu'un mettra à jour à partir de Management Studio). Tout fonctionne parfaitement (et rapidement) mais je me demande si l'un de mes SP échoue. Devrais-je m'inquiéter du tout? – Novitzky

+0

Je vous suggère de tester en modifiant la procédure ou l'insertion de données qui garantira l'échec du processus. Ensuite, vous saurez ce qui va arriver. – HLGEM

+0

Merci. C'est exactement ce que je vais faire. Comme je l'ai dit avant je dois utiliser le curseur (sinon ce serait trop de changements dans mon application) mais je peux changer mes SP. Merci quand même. – Novitzky

Questions connexes