Délai d'expiration de transaction SQL Server

9

Existe-t-il un moyen dans SQL Server 2008 R2 de provoquer un délai d'attente pour une modification de base de données impliquant une transaction? Nous avons un scénario où notre code d'application se bloque ou lève une exception et ne parvient pas à effectuer une restauration ou une validation. Cela provoque alors le blocage d'autres sessions en attendant la fin de la transaction.

David Gray Wright
la source

Réponses:

20

Étendre la réponse de Mark ...

Lorsqu'un événement de délai d'expiration du client se produit (.net CommandTimeout par exemple), le client envoie un "ABORT" à SQL Server. SQL Server abandonne alors simplement le traitement des requêtes. Aucune transaction n'est annulée, aucun verrou n'est libéré.

Maintenant, la connexion est renvoyée au pool de connexions, elle n'est donc pas fermée sur SQL Server. Si cela se produit (via KILL ou redémarrage du client, etc.), les transactions + les verrous seront effacés. Notez que sp_reset_connection ne les effacera pas ou ne les effacera pas, même s'il est annoncé pour le faire

Ces détritus de l'avortement bloqueront d'autres processus.

La façon de rendre les transactions + verrous SQL Server claires sur le délai d'expiration du client (strictement, les événements ABORT) consiste à utiliser SET XACT_ABORT ON.

Vous pouvez vérifier cela en ouvrant 2 fenêtres de requête dans SSMS:

Fenêtre 1:

Dans le menu Query..Query Options, définissez un délai d'expiration de 5 secondes, puis exécutez cette

BEGIN TRAN
UPDATE sometable WITH (TABLOCKX) SET foo = foo WHERE 1 = 0;
WAITFOR DELAY '00:00:10' -- just has to be longer then timeout

Fenêtre 2, cela attendra pour toujours (ou atteindra votre délai d'attente)

SELECT * FROM sometable

SET XACT_ABORT ON a aussi des effets secondaires intéressants:

  • @@ TRANCOUNT est défini sur zéro lors de la restauration implicite mais l'erreur 266 est supprimée (cela se produit si @@ TRANCOUNT est différent à l'entrée et à la sortie d'un proc stocké)
  • XACT_STATE sera -1 (c'est "condamné")

La combinaison de cela signifie que vous ne pouvez pas utiliser SAVEPOINTS (bien que je ne me souvienne pas du comportement exact) pour les validations / annulations partielles. Qui me convient

Liens SO sur SET XACT_ABORT:

Sur les proc stockés imbriqués:

Sur sp_reset_connection:

gbn
la source
L'avenir dit bonjour! "Notez que sp_reset_connection ne les effacera pas ou ne les effacera pas, même s'il est annoncé pour le faire" - Je ne crois pas que ce soit plus vrai dans les versions à jour de SQL Server?
kamilk
11

Je réponds à cette question avec hésitation car il n'y a pas suffisamment d'informations dans votre description du problème pour être sûr à 100% que c'est le meilleur conseil. "Suspend ou lève une exception" suggère que la source du problème n'est pas bien comprise, alors soyez prudent.

La solution la plus simple à cela est probablement SET XACT_ABORT ON.

XACT_ABORTdétermine si SQL Server annulera une transaction en cas d'erreur d'exécution. La valeur par défaut SET XACT_ABORT OFFannulera uniquement l'instruction qui a provoqué une erreur, laissant toute transaction parent ouverte.

L'effet secondaire "gotcha" du paramètre par défaut est qu'un délai d'attente peut provoquer exactement le même problème, une transaction ouverte qui est la responsabilité des clients à gérer et à annuler. Si le client n'essaie pas / catch / rollback, la transaction restera ouverte jusqu'à ce qu'elle soit traitée avec (et je cite @gbn) l'ultra-violence de KILL <spid>.

Les articles d' Erland Sommarskog souvent cités sur la gestion des erreurs dans SQL Server contiennent tous les antécédents et la stratégie dont vous avez besoin pour gérer ces scénarios et plus encore.

Modifier (commentaire suivant): Pour identifier les transactions ouvertes, sp_whoisactive est probablement la fonctionnalité la plus complète.

Mark Storey-Smith
la source
J'ai trouvé, avec quelques recherches sur Google, des moyens de trouver des transactions ouvertes lorsque le blocage se produit - c'est peut-être la meilleure solution. C'est pour trouver la cause de la transaction non fermée dans le code et corriger les trous dans le code. Pour référence pour les autres. DBCC OPENTRAN renvoie la transaction active la plus ancienne -> msdn.microsoft.com/en-us/library/ms182792.aspx Ou quelque chose de plus comme ça? -> weblogs.sqlteam.com/mladenp/archive/2008/04/29/…
David Gray Wright
J'ai toujours pensé Erland ne rendait pas justice à la SET XACT_ABORT sommarskog.se/error-handling-I.html#XACT_ABORT
gbn