2009-05-29 7 views
1

J'ai une routine qui met à jour mon entité commerciale. La mise à jour implique environ 6 tables différentes. Toutes les commandes sont en cours d'exécution dans une transaction.Comment éviter ces blocages?

Récemment, j'ai dû ajouter du code dans la routine qui accède à une table de recherche à partir de la base de données. Le code de recherche existait déjà dans un autre objet métier, j'ai donc utilisé cet objet métier. Par exemple:

Using tr As DbTransaction = myConnection.BeginTransaction() 
    ExecuteCommand1(tr) 
    ExecuteCommand2(tr) 
    If myLookupTable.GetLookupTable().FindById(id).HasFlagSet Then 
     ExecuteCommand3(tr) 
    End If 
End Using 

Toutefois, l'objet métier de la table de correspondance est bloqué/deadlocks. Je pense que c'est parce qu'il n'a pas de référence à la transaction utilisée par la routine d'origine. Après avoir fait des recherches, j'ai tenté de mettre la logique de la table de recherche dans sa propre transaction en réglant le IsolationLevel sur ReadUncommitted. Cela m'a donné les résultats que je désirais. Cependant, après de plus amples recherches, je suis maintenant en train de deviner si j'ai implémenté cela correctement.

En supposant qu'une référence à la transaction active n'est pas disponible pour mon objet de table de recherche, ce que j'ai décrit est-il considéré comme la meilleure pratique? Je sens que je pourrais manquer quelque chose.

+0

Est-ce que command1 ou command2 fait quelque chose avec le lookuptable? –

+0

Non, ils ne le font pas. Ils ne lisent même pas. Ils fonctionnent avec des tables qui ont un FK à la table de recherche cependant.Rien de tout cela ne suggère intuitivement un problème de verrouillage.

Répondre

3

Si vous faites une lecture au milieu de votre transaction, vous devriez le faire dans le contexte de la transaction, sans utiliser une transaction différente et des lectures sales. Heureusement, il existe une solution simple: au lieu d'utiliser les objets de transaction ADO.Net, utilisez l'objet .Net TransactionScope. Le code ADO.Net est sensé et enrôlera toutes vos opérations dans cette transaction, y compris vos autres lectures de composants. Assurez-vous simplement que votre objet métier n'ouvre pas une connexion différente, cela entraînera une tentative d'escalade de la transaction existante vers une transaction distribuée et l'inscription de la nouvelle connexion dans celle-ci. L'alternative est de transmettre votre paire SqlConnection/SqlTransaction à chaque appel, mais cela se propage horriblement partout dans votre code.

0

Si c'était moi, je réécrirais la logique afin que je n'ai pas à faire une lecture non validée.

0

La règle d'or pour éviter les blocages est de toujours prendre les verrous de table dans le même ordre dans chaque transaction. Regardez donc le code dans les autres transactions pour voir dans quel ordre ils prennent les verrous de table; alors assurez-vous d'utiliser le même ordre dans votre transaction.

0

Apparemment, votre recherche tente d'accéder à une ou plusieurs lignes qui sont exclusivement verrouillées par la transaction tr. Si vous utilisez une transaction readuncommitted ou bien utilisez WITH (NOLOCK) dans votre requête de recherche, vous verrez toutes les modifications non validées par les transactions qui pourraient se produire et affecter votre logique de recherche. Donc, je ne suis pas sûr à quel point cela serait souhaitable.

Je pense qu'il est préférable de trouver un moyen de s'assurer que votre requête de recherche participe à la transaction en cours si vous avez besoin de faire la recherche au cours de cette transaction. Si toutes ces opérations doivent être exécutées dans le même thread, une chose que vous pouvez faire est de stocker l'objet de transaction dans le stockage local de threads lorsque vous en créez un et que la méthode GetLookupTable vérifie le stockage local du thread pour un objet de transaction. est un ensemble de transactions, vous pouvez obtenir la connexion à partir de cet objet de transaction. Sinon, vous créez une nouvelle connexion. De cette façon, votre recherche fera partie de cette transaction et elle devrait exécuter sa logique sans être bloquée par la transaction en cours et bloquer à son tour la transaction en cours et entraîner ainsi un blocage.

Questions connexes