33 votes

NHibernate avec TransactionScope

Quelqu'un peut-il me donner un aperçu rapide de l'utilisation de TransactionScope avec NHibernate ? Dois-je faire quelque chose de spécial avec la session/IEnlistmentNotification/etc. pour que cela fonctionne ? Y a-t-il des pièges dont je dois me méfier ? Par exemple, puis-je remplacer toutes mes transactions hibernate :

var transaction = session.BeginTransaction();
try
{
    // code
    transaction.Commit();
}
catch (Exception)
{
    transaction.Rollback();
}

avec ce.. :

using (var scope = new TransactionScope())
{
    // code
    scope.Complete();
}

18voto

Iain Points 3903

J'utilise nHibernate 2.1 depuis un certain temps et, après quelques problèmes de production et l'essai de plusieurs variantes, nous avons opté pour la méthode suivante, comme indiqué dans le tableau ci-dessous. Éviter les fuites de connexion avec NHibernate et TransactionScope :

        using (var scope = new TransactionScope(TransactionScopeOption.Required))
        {
            using (var session = sessionFactory.OpenSession())
            using (var transaction = session.BeginTransaction())
            {
                // do what you need to do with the session
                transaction.Commit();
            }
            scope.Complete();
        }

Comme nous utilisons MSMQ et WCF, nous avons dû utiliser la transaction ambiante.

Nous avons constaté que le fait de ne pas utiliser session.BeginTransaction() provoquait une fuite de connexion. Nous avons également constaté que la réutilisation d'une session après la validation d'une transaction provoquait une situation de concurrence (nHibernate n'est pas thread safe et les DTSC Commits/Rollbacks se produisent sur un thread d'arrière-plan).

7voto

Adam Fyles Points 5187

Je l'ai testé en utilisant différents fournisseurs et ça marche. Si vous n'avez pas "scope.Complete()", la transaction sera annulée. Il se peut que vous deviez faire tourner MSDTC sur la ou les machines concernées s'il y a plus d'une ressource durable. Dans ce cas, MSDTC détectera automatiquement les transactions ADO.NET ambiantes et gérera l'ensemble.

6voto

user133599 Points 51

Ce qui précède fonctionne bien si vous utilisez un fournisseur de connexion qui prend en charge l'utilisation d'un gestionnaire de transactions léger, tel que SQL Server 2005/2008.

Si vous utilisez SQL Server 7/2000, toutes vos transactions deviendront des transactions distribuées, même si vous ne touchez qu'une seule base de données/ressource. Ce n'est probablement pas ce que vous souhaitez dans la plupart des cas, et cela vous coûtera cher en termes de performances.

Vérifiez donc si votre combinaison de fournisseur de connexion et de serveur de base de données est adaptée à une utilisation avec TransactionScope.

5voto

Piper Points 121

Je pense que vous pouvez remplacer les transactions NHibernate par ce système, à condition de respecter certaines contraintes, comme certains l'ont déjà dit :

  • Utilisez une version raisonnablement récente de NHibernate ( >=3.1 ).
  • Le fournisseur de données ADO.NET sous-jacent doit supporter TransactionScope (ok pour SQL-Server, Oracle >= 10 avec ODP.NET).
  • Créez votre session NH en le TransactionScope pour s'assurer qu'il est enrôlé.
  • Gérer NHibernate chasse d'eau manuellement. Voir aussi ici y ici .
  • Préparez les transactions distribuées. Si vous créez plusieurs sessions dans une même étendue, la transaction initialement locale peut être promue en transaction distribuée. J'ai vu cela se produire même avec les mêmes chaînes de connexion sur une base de données Oracle 11.2 utilisant ODAC 11.2.0.3.20. Sur SQL-Server 2008 R2, la promotion n'a pas eu lieu. (BTW, on peut voir cela en regardant Transaction.Current.TransactionInformation.DistributedIdentifier qui est nul pour les transactions locales). Bien que les transactions distribuées présentent certains avantages, elles sont plus coûteuses et leur mise en place est un peu plus difficile. (Voir ici comment le faire pour Oracle). Pour être sûr que la promotion ne se produise jamais dans Oracle, définissez " Transaction promouvable \=local" dans votre chaîne de connexion. Cela crée une exception si un code tente de le faire.

J'espère que c'est tout ;-)

PS : J'ai ajouté les détails d'Oracle parce qu'ils me concernent et que d'autres pourraient en profiter.

1voto

Rohit Agarwal Points 1930

De plus, si vous utilisez TransactionScope, passez à la version 2.1 de NHibernate. Ce n'est qu'avec la 2.1 que NH a vraiment obtenu une bonne intégration avec TransactionScope.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X