2010-11-16 7 views
15

J'essaie d'écrire dans un fichier journal à l'intérieur d'une transaction afin que le journal survive même si la transaction est annulée.Enregistrement TSQL dans la transaction

Code --start

begin tran

[insérer quelque chose] dans dbo.logtable

[[code principal ici]]

rollback

commit

- code de fin

Vous pourriez dire juste faire le journal avant que la transaction commence mais ce n'est pas aussi facile parce que la transaction commence avant que ce S-Proc soit exécuté (c.-à-d. le code fait partie d'une transaction plus importante)

Donc, en bref, est-il possible d'écrire une instruction spéciale dans une transaction qui ne fait pas partie de la transaction. J'espère que ma question a un sens.

+0

S'il vous plaît jeter un oeil à http://stackoverflow.com/questions/3725356/suppress-transaction-in-stored-procedure –

Répondre

12

Utilisez une variable de table (@temp) pour conserver les informations de journal. Les variables de table survivent à une annulation de transaction.

Voir this article.

+0

Juste ce que j'allais suggérer. Je l'ai utilisé avec succès plusieurs fois. – HLGEM

+0

Le problème avec ceci est que si quelque chose d'autre se produit comme un délai de connexion ou un délai d'attente d'exécution, il ne vous restera plus de journaux. – Talon

2

Je fais cela de deux façons, selon mes besoins à ce moment-là. Les deux impliquent l'utilisation d'une variable qui conserve sa valeur à la suite d'une restauration.

1) Créez une valeur DECLARE @Log varchar(max) et utilisez ceci: @SET @ Log = ISNULL (@ Log + ';', '') + 'Votre nouveau journal d'informations ici' . Keep appending to this as you go through the transaction. I'll insert this into the log after the commit or the rollback as necessary. I'll usually only insert the @Log value into the real log table when there is an error (in the CATCH` bloc) ou Si j'essaye de déboguer un problème.

2) créer un DECLARE @LogTable table (RowID int identity(1,1) primary key, RowValue varchar(5000). Je l'insère dans ce que vous progressez dans votre transaction. J'aime utiliser la clause OUTPUT pour insérer les ID réels (et d'autres colonnes avec des messages, comme 'SUPPR. Élément 1234') des lignes utilisées dans la transaction dans cette table avec. Je vais insérer cette table dans la table de journal réelle après la validation ou l'annulation si nécessaire.

+0

Les deux sont bons sauf que je n'ai pas un accès facile à la partie transaction. Fondamentalement, j'essaie de déboguer un programme écrit en C#. – Arvid

+1

(terminons ceci :-) Le code C# commence une transaction, puis appelle un s-proc, et à la fin il valide ou annule la transaction. J'ai seulement un accès facile au s-proc et j'espérais pouvoir y faire du code de débogage qui survivrait à une annulation – Arvid

+0

vous pourriez essayer d'utiliser [xp_cmdshell (Transact-SQL)] (http://msdn.microsoft.com /en-us/library/ms175046.aspx) (mais cela peut être désactivé comme un risque de sécurité) pour les inclure dans votre procédure: 'EXEC xp_cmdshell echo 'votre message ici' >> log.txt' pour écrire dans un fichier . vous pouvez également essayer d'utiliser un paramètre de sortie @ErrorInfo varchar (max) 'où vous renvoyez l'information d'erreur au programme C# pour qu'il puisse l'enregistrer. –

1

Si la transaction parente revient en arrière, les données de journalisation seront également restaurées - le serveur SQL ne prend pas en charge les transactions imbriquées appropriées. Une possibilité consiste à utiliser une procédure stockée CLR pour effectuer la journalisation. Cela peut ouvrir sa propre connexion à la base de données en dehors de la transaction et entrer et valider les données du journal.

+0

L'utilisation de la procédure d'enregistrement CLR est l'une des meilleures solutions. Si seulement il était possible d'obtenir en quelque sorte automatiquement les valeurs réelles des paramètres, le sproc a été appelé avec .. nous pouvons toujours rêver. –

7

Voir Logging messages during a transaction pour une autre solution basée sur sp_trace_generateevent qui ne nécessite pas de variable scope @table (ce qui n'est pas toujours possible) ou lorsque les limites de transaction sont hors de contrôle.

+0

On dirait que cela va fonctionner. Merci à tous pour les réponses rapides. – Arvid

0

Si vous souhaitez émuler le comportement des transactions imbriquées, vous pouvez utiliser des transactions nommées:

begin transaction a 

create table #a (i int) 

select * from #a 
save transaction b 

create table #b (i int) 
select * from #a 
select * from #b 

rollback transaction b 

select * from #a 
rollback transaction a 

Dans SQL Server si vous voulez un « sous-transaction », vous devez utiliser save transaction xxxx qui fonctionne comme un point de contrôle oracle.

+3

Cette réponse ne répond pas du tout à la question. Le PO ne demande pas de sous-transaction, bien au contraire. Il veut qu'une opération soit exclue du contexte de la transaction et engagée directement dans la base de données. – Tipx

+0

ma réponse était au commentaire ci-dessus - et je pense que répondu assez succinctement –

Questions connexes