web-dev-qa-db-fra.com

C # contrôler une transaction sur plusieurs bases de données

Supposons que j'ai une application Windows Form qui se connecte aux bases de données n, avec des connexions n ouvertes simultanément.

Ce que je recherche, c'est de faire une transaction avec toutes ces bases de données en une seule fois.

Par exemple, si je devais avoir 2 connexions à la base de données:

using (ITransaction tx1 = session1.OpenTransaction())
{
    using (ITransaction tx2 = session2.OpenTransaction())
    {
        // Do the query thingy here
    }
}

Écrire tout ce qui est bien au début, mais les choses deviennent un peu redondantes quand je voulais interroger ça et là, sans parler de la possibilité d'ajouter une nouvelle connexion.

Ce que je voulais, c'est boucler toute la session enregistrée et la boucler dans un service, probablement quelque chose comme ceci:

class TransactionManager
{
    private ISession[] _sessions;

    public TransactionManager(string[] connectionStrings)
    {
        // Initialize the sessions here
    }

    public function DoTransaction(string query)
    {
        foreach (ISession session in _sessions)
        {
            // What to do here? Using? Try-catch?
        }
    }
}

Si je devais utiliser using dans la boucle foreach, cela signifierait que si la connexion A réussissait mais pas la connexion B, alors seule la connexion B serait annulée.

26
Samuel Adam

Il semble que vous réinventiez TransactionScope . Faire tout cela sous une unité de travail est simple *:

  using (TransactionScope scope = new TransactionScope())
  {
     ... Do Stuff with Connection 1 using SqlDataReader
     ... Do Stuff with Connection 2 using Entity Framework
     ... Do Stuff with Connection 3 on another Oracle Database
     ... And for good measure do some stuff in MSMQ or other DTC resource
     scope.Complete(); // If you are happy
  }

Stuff n'a pas du tout besoin d'être en ligne - il peut être dans une classe différente ou un assembly différent. Il n'est pas nécessaire d'enregistrer explicitement les connexions de base de données ou de file d'attente avec TransactionScope - tout se passe automagically, à condition que les ressources que vous utilisez soient capables de s'inscrire dans une transaction ambiante .

Maintenant, les petits caractères:

  • * Chaque fois que vous utilisez plusieurs connexions à la base de données simultanément, ou différentes chaînes de connexion, ou plusieurs technologies, cela nécessitera validation en 2 phases et passera à une transaction DTC afin de garantir ACID à travers les ressources. DTC lui-même a beaucoup plus de petits caractères et en pose beaucoup plus défis dans un réseau d'entreprise , comme pare-fe , clustering , configuration de sécurité et bugs .
  • Cependant, avec les transactions légères sur MS SQL Server, si vous pouvez conserver toutes vos connexions en utilisant la même base de données et les mêmes paramètres de chaîne de connexion, et fermer chaque connexion avant d'ouvrir la suivante, alors vous pouvez éviter le DTC .

  • Le maintien d'une transaction sur plusieurs ressources ACID maintiendra invariablement des verrous sur ces ressources, jusqu'à ce que la transaction soit validée ou annulée. Souvent, cela ne favorise pas le bon voisinage dans une entreprise à volume élevé, alors assurez-vous de considérer les conséquences du verrouillage.

  • Si le Stuff se fait sur plusieurs threads, vous devrez vous connecter DependentTransaction

  • Un dernier point à mentionner est le niveau d'isolement par défaut avec TransactionScope est Serializable, qui est sujet aux blocages. Dans la plupart des scénarios non critiques, vous pourrez probablement le faire passer à Read Committed .

38
StuartLC

utilisez TransactionScope, il se chargera de valider ou d'annuler toutes les transactions incluses:

using (var ts = new TransactionScope())
{
   ... // your old code

   ts.Complete()
}
6
Zdravko Danev