web-dev-qa-db-fra.com

Pourquoi essayer de ne pas supprimer l'exception dans la gâchette

J'ai une gâchette sur une table (source) que les données doivent être copiées sur l'autre (cible) dans une autre base de données. J'essaie de mettre en œuvre un processus de synchronisation personnalisé pour les données: je veux que la base de données cible (tableau) soit à jour pour la base de données source (tableau). J'ai 3 cents tables pour se synchroniser. Certains ont alors une structure de données physique différente. Je ne peux pas utiliser les approches standard de SQL Server (réplication, DTS ...) en raison de différents schémas de données et autres restrictions (heure à mettre en œuvre, problèmes d'environnement ...). Mon objectif est que ce déclencheur ne doit pas avoir d'impact sur INSERT, Supprimer, mettre à jour des enregistrements dans une table source. J'ai essayé tellement la solution:

CREATE TRIGGER dbo.MyTrigger
...
   AFTER INSERT
....
BEGIN TRY
     --RAISERROR('Test error', 16, 2)
END TRY
BEGIN CATCH
  -- nothing
END CATCH

J'ai inséré RAISEERROR pour simuler une erreur. J'espérais, try/catch supprimé que l'erreur et l'enregistrement ont été insérées (supprimées ou mises à jour) avec succès. Ne pas. Ça ne marche pas. J'ai eu une erreur:

Une erreur a été soulevée lors de l'exécution de la gâchette. Le lot a été abandonné et la transaction de l'utilisateur, le cas échéant, a été renvoyée.

Est-il possible de réaliser ma solution de cette manière. Comment puis-je attraper et tenir (supprimer) toute erreur dans mon déclencheur?

Quel sens utiliser try/catch Dans la gâchette si cela ne fonctionne pas?

4
garik

La transaction est condamnée avec à peu près à toute exception et doit être renvoyée.

De - "Utilisation d'essayer ... attraper dans transact-sql" sur msdn

À l'intérieur d'un essai ... Construit Catter, les transactions peuvent entrer un état dans lequel la transaction reste ouverte mais ne peut pas être commise. La transaction ne peut effectuer aucune mesure qui générerait une écriture sur le journal des transactions, telles que la modification des données ou la tâche de rétablir un point de sauvegarde. Cependant, dans cet état, les serrures acquises par la transaction sont maintenues et la connexion est également ouverte. Les effets de la transaction ne sont pas inversés jusqu'à ce qu'une instruction Rollback soit émise ou jusqu'à la fin du lot et que la transaction soit automatiquement rémunérée par le moteur de base de données. Si aucun message d'erreur n'a été envoyé lorsque la transaction est entrée dans un état incorrectoire, lorsque le lot se termine, un message d'erreur sera envoyé à l'application client indiquant qu'une transaction incorrecte a été détectée et roulée en arrière.

Une transaction entre dans un état incorrect à l'intérieur d'un bloc d'essai lorsqu'une erreur se produit autrement terminé la transaction. Par exemple, la plupart des erreurs d'une instruction Langue de définition de données (DDL) (telle que CREATE TABLE) ou la plupart des erreurs qui se produisent lorsque SET XACT_ABORT est défini sur On, terminez la transaction à l'extérieur d'un bloc d'essai, mais faites une transaction incorrectable à l'intérieur d'un bloc d'essai. .

Cet exemple montre pourquoi. Xact_state () n'enregistre pas une transaction implicite (par exemple, aucun tran de début explicite)

CREATE TABLE TrgTest (gbn int NOT NULL);
GO
CREATE TRIGGER TRG_TrgTEst_I ON TrgTest AFTER INSERT
AS
BEGIN TRY
     SELECT '1', @@TRANCOUNT, XACT_STATE();
     RAISERROR('Test error', 16, 2);
END TRY
BEGIN CATCH
     SELECT '2', @@TRANCOUNT, XACT_STATE();
END CATCH
GO

BEGIN TRANSACTION
INSERT TrgTest VALUES (1)
SELECT 'will not run'
GO
SELECT 'next batch'
GO


BEGIN TRY
    BEGIN TRANSACTION
    SELECT 'a', @@TRANCOUNT, XACT_STATE();
    INSERT TrgTest VALUES (1)
    SELECT 'b', @@TRANCOUNT, XACT_STATE();
END TRY
BEGIN CATCH
    SELECT ERROR_MESSAGE()
    SELECT 'c', @@TRANCOUNT, XACT_STATE();
END CATCH
GO

DROP TABLE TrgTest;
6
gbn

J'ai trouvé une solution de contournement légèrement risquée qui supprime les "transactions non acquises" qui se produisent dans un déclencheur DML.

ATTENTION: Il est généralement dangereux de supprimer les erreurs de transaction dans une gâchette, alors pensez longtemps et difficile avant de tenter de le faire. Cette méthode est extrêmement dangereuse s'il existe d'autres déclencheurs DML sur la même table, car vous pouvez être commettre des données non valides qu'un autre déclencheur a l'intention de rouler.

Pour supprimer des erreurs graves qui se produisent dans votre déclencheur DML:

  1. Commettre la transaction préexistante implicite qui représente la commande initiale insertion/mise à jour/Supprimer
  2. À l'intérieur d'un bloc d'essai, utilisez sp_executesql pour tenter votre entreprise risquée.
  3. À la fin de votre déclencheur, commencez une nouvelle transaction. Cela empêchera l'erreur 3609: la transaction s'est terminée dans la gâchette.
0
Beekir