Pratique SQL Server

Verrous applicatifs pour une opération métier

Coordonnez les workers avec sp_getapplock, traitez les codes de retour et distinguez exclusion temporaire et idempotence durable.

Deux workers peuvent décider qu'une facture est prête à être finalisée avant que l'un d'eux enregistre le résultat. Une contrainte unique peut protéger le numéro final sans coordonner toutes les étapes intermédiaires. Un verrou applicatif fournit une ressource nommée permettant à des sessions SQL Server coopérantes de sérialiser cette opération métier.

Définir la ressource et sa durée

Nommez la plus petite unité nécessitant une exclusion, par exemple invoice:481 plutôt que all-invoices. Un nom global sérialise inutilement des clients indépendants. À l'inverse, des orthographes différentes créent des verrous indépendants. Centralisez la construction du nom et ajoutez le locataire lorsque les numéros ne sont uniques que dans son périmètre.

La ressource appartient à une base et à un espace de noms de principal de base. Le même texte dans deux bases ne crée pas une exclusion commune. La comparaison des noms distingue la casse. Utilisez une représentation canonique et respectez la longueur documentée pour éviter les collisions dues à une troncature.

La propriété par transaction convient généralement à une opération courte limitée à la base. Commit ou rollback libère alors le verrou. Une propriété par session peut convenir à certains scénarios, mais la libération explicite et le pool de connexions deviennent des éléments de correction. Une connexion réutilisée n'est pas une frontière métier.

Vérifier chaque acquisition

Exécutez ce modèle dans une base de test sans transaction extérieure. Remplacez l'emplacement indiqué par la véritable opération courte. Le contrôle du code de retour empêche d'exécuter le travail protégé après un échec d'acquisition.

IF @@TRANCOUNT <> 0
    THROW 50000, 'This example owns its transaction.', 1;
SET XACT_ABORT ON;
BEGIN TRY
    BEGIN TRAN;
    DECLARE @rc int;
    EXEC @rc = sys.sp_getapplock
        @Resource = N'invoice:481',
        @LockMode = 'Exclusive',
        @LockOwner = 'Transaction',
        @LockTimeout = 5000,
        @DbPrincipal = 'public';
    IF @rc < 0
        THROW 50001, 'Application lock was not acquired.', 1;
    -- Read durable operation record; perform short database work.
    SELECT @rc AS LockResult;
    COMMIT;
END TRY
BEGIN CATCH
    IF XACT_STATE() <> 0 ROLLBACK;
    THROW;
END CATCH;

Un code non négatif indique une acquisition réussie. Un code négatif signale notamment un délai dépassé, une annulation ou une sélection comme victime de deadlock. Le modèle annule la transaction pour tout échec. Le code de production peut classifier ces situations pour la journalisation et les tentatives bornées, mais ne doit jamais les traiter comme une autorisation de continuer.

Les cinq secondes concernent uniquement l'acquisition de ce verrou. Elles ne limitent pas les attentes de verrous de lignes ultérieures, le réseau ou la durée totale de l'opération. Définissez un budget global distinct et garantissez le nettoyage transactionnel après annulation.

Pour tester, ouvrez dans A une transaction et acquérez la ressource sans terminer. B doit échouer après son délai. Annulez A et relancez B : l'acquisition doit réussir. Testez aussi deux ressources de facture différentes et vérifiez leur indépendance. Fermez explicitement toute transaction laissée ouverte pour l'expérience.

Conserver les garanties durables

Seuls les chemins acquérant la même ressource respectent l'exclusion. Une modification administrative directe ou une ancienne version applicative peut contourner cette convention. Gardez les contraintes uniques, clés étrangères et contrôles des transitions autorisées. Le verrou organise la coopération ; il ne remplace pas le modèle de données.

Après libération, il ne mémorise pas non plus le succès. Si le client perd la réponse après commit, une nouvelle tentative peut reprendre le verrou. Enregistrez donc un identifiant d'opération durable et son résultat dans la transaction métier. Sous le verrou, recherchez d'abord cet enregistrement et restituez le résultat existant en cas de doublon.

Ne gardez pas la transaction ouverte pendant un appel à un prestataire de paiement. Un rollback SQL n'annule pas un débit externe réussi. Inscrivez plutôt un élément d'outbox dans la transaction et utilisez un chemin de livraison idempotent. Si plusieurs ressources sont nécessaires, acquérez-les toujours dans le même ordre : les verrous applicatifs participent aussi aux deadlocks. Mesurez les échecs, les attentes et l'âge des transactions pour vérifier que seules les opérations portant sur la même clé se sérialisent.

Références techniques: Microsoft Learn: sp_getapplock · Microsoft Learn: sp_releaseapplock.

Question sur cet article

Vous avez une question sur ce sujet ?

Expliquez ce que vous évaluez ou le point qui vous bloque. Nous vous répondrons avec une recommandation pratique.

Inquiries are not enabled in this preview.

Poser une question sur cet article