2010-01-29 6 views
6

J'ai du code dans un déclencheur après insertion qui peut potentiellement échouer. Une telle défaillance n'est pas cruciale et ne devrait pas annuler la transaction. Comment puis-je piéger l'erreur dans le déclencheur et faire exécuter le reste de la transaction normalement?Echec de la désactivation du déclencheur TSQL

L'exemple ci-dessous montre ce que je veux dire. Le déclencheur crée intentionnellement une condition d'erreur avec le résultat que l'insertion d'origine ("1") n'insère jamais dans la table. Try/Catch n'a pas l'air de faire l'affaire. Un semblable, older stack overflow question n'a pas donné de réponse sauf pour "empêcher l'erreur de se produire en premier lieu" - ce qui n'est pas toujours possible/facile.

D'autres idées?

create table test 
(
    a int not null 
); 
go 

create trigger testTrigger on test 
after insert as 
begin 
    insert into test select null; 
end; 
go 

insert into test values (1); 
+1

/Catch ne fonctionne pas? – cjk

+0

@ck: car les violations de contraintes à l'intérieur des déclencheurs annihilent les transactions. – Quassnoi

Répondre

2

Un déclencheur ne peut pas échouer et la transaction est toujours restaurée. Vous avez quelques options pour vous assurer que le déclencheur n'échoue pas.

1 - Vous pouvez faire en sorte que l'après ne manque pas en dupliquant la logique de vérification des contraintes et ne pas tenter une opération qui serait contraire aux contraintes:

-à-dire

INSERT INTO test WHERE val IS NOT NULL 

2 - Vous pouvez différer l'action potentiellement défaillante en utilisant un modèle de conception de file d'attente dans lequel les actions qui peuvent ou non échouer sont mises en file d'attente par mise en file d'attente sur une table où l'opération de mise en file d'attente ne peut pas échouer.

à savoir

INSERT INTO ACTION_QUEUE (action, parameters) VALUES ('INSERT INTO TEST', val) 
+0

J'ai peur que ça soit le seul moyen. C'est difficile cependant. S'il vous plaît voir mon commentaire à la réponse de Quassnoi ci-dessous. – BuschnicK

+0

@BuschnicK Faire des déclencheurs est l'une des choses les plus invasives que vous pouvez faire dans un système. Cela fait partie du schéma de base de données pour forcer le comportement de la base de données et vous le faites dans la base de données de quelqu'un d'autre. Ils ont leur place, mais je ne pense pas que cet usage soit approprié si vous ne pouvez pas vous assurer qu'ils se comportent bien.Franchement, si vous utilisez un déclencheur comme votre seul mécanisme pour expédier des modifications, si le déclencheur devait échouer en silence, vos modifications ne seraient pas expédiées, mais la transaction pourrait se terminer et vous perdriez le "message" de changement de données, comment re-synchroniser vos données de manière fiable de toute façon? –

+0

@BuschnicK Vous feriez mieux d'examiner une sorte de capture de données de modification ou toute autre technique ETL pour comparer les changements depuis la dernière capture instantanée. –

1

En raison de la déclencheurs sont mises en œuvre ainsi SQL Server, toutes les violations de contraintes dans les déclencheurs les transactions vouer ne.

C'est la même chose que faire:

DROP TABLE test 

CREATE TABLE test 
(
     a INT NOT NULL 
) 

GO 

SET XACT_ABORT ON 
GO 

BEGIN TRANSACTION 

BEGIN TRY 
     INSERT 
     INTO test 
     SELECT NULL 
END TRY 
BEGIN CATCH 
     INSERT 
     INTO test 
     SELECT 1 
END CATCH 

qui se traduit par une transaction condamnée, sauf qu'il n'y a aucun moyen de désactiver XACT_ABORT à l'intérieur d'un déclencheur.

SQL Server manque également de transactions autonomes.

C'est une autre raison pour laquelle vous devriez mettre toute votre logique dans les procédures stockées plutôt que dans les déclencheurs.

+0

en fait vous n'avez pas de transactions condamnées si vous n'utilisez pas try..catch. –

+0

@Alex: bien sûr, l'opération est simplement annulée de manière atomique. C'était juste pour montrer ce qui se passe. – Quassnoi

+0

Comment les procédures stockées aident-elles? Je pensais que quelque chose que le déclencheur appelle la procédure stockée ... Pour donner un peu d'information de base de ce que je suis en train d'archiver ici: Nous avons un système ERP fourni par le fournisseur et que nous voulons mettre à jour les données à jour ce sont des tables. Nous attachons des triggers à leurs tables, massons les données et les copions dans notre propre base de données. Nous voulons garantir que nos déclencheurs n'échoueront jamais car cela causerait des problèmes dans le système ERP d'origine. – BuschnicK

0
  1. Vous pouvez activer XACT_ABORT de l'intérieur de la gâchette (utilisation précaution)
  2. Vous pouvez avoir la gâchette appeler une procédure stockée. (Je suis en train de lutter avec le problème inverse: je veux que la transaction soit annulée, mais parce que la logique est dans un SP appelé par le déclencheur, et non le déclencheur lui-même, cela ne se produit pas.)
Questions connexes