2009-11-23 6 views
0

Je rencontre un problème avec une condition de concurrence lors de l'enregistrement asynchrone dans la base de données en utilisant NHibernate. D'abord, une insertion dans la base de données est effectuée de manière asynchrone, où l'identifiant unique est généré automatiquement. Avant cette insertion revient au thread principal avec l'objet maintenant persisté qui a l'ID généré par base de données unique, l'objet dans la mise à jour d'une certaine manière. La mise à jour échouera si j'appelle session.Update car l'objet à mettre à jour n'a pas encore de valeur d'identifiant. Si j'appelle SaveOrUpdate, il en résultera évidemment une insertion au lieu d'une mise à jour car le champ id de mon entité est égal à la propriété non-value-value. Espérons que ce code rend la situation plus claire:Nhibernate, multithread et conditions de concurrence

Entity entity = new Entity() 
//update some fields 
entity.PropertyTwo = "new value"; 
//dataObject as the database auto-generated Id 
//insert new row asynchronously in different thread 
Entity entity.Id = dao.save(entity.Clone()).Id 

//before the the entity is returned from the database, the entity might be updated 
entity.Property = 'new value'; 
//entity might be sent without an Id since the first asynch call has not returned yet. 
//update asynchronously in another thread 
Object dataObject = dao.Update(entity); //fails because Id is not set yet 

Une solution consiste à générer l'identifiant unique dans le code avant de sauvegarder. Dans ce cas, l'application gère l'incrémentation de l'identifiant unique par opposition à la base de données. D'autres façons de gérer cela?

Répondre

1

On dirait que vous pourriez créer plusieurs threads dans une seule session NHibernate. Les sessions dans NHibernate sont pas thread sûr. Vous ne devez jamais accéder à la même session dans deux threads concurrents. Essayez de créer une session distincte dans votre nouveau thread et voir si cela résout votre problème.

Consultez le NHibernate documentation section 10.2.

+0

Non Je crée une session par thread. La condition de concurrence survient si une mise à jour est mise à jour sur une entité avant la fin de l'insertion. – infinity

+0

Gardez à l'esprit que chaque appel de base de données se produit sur un thread différent. Si une mise à jour est tentée sur un deuxième thread avant la fin de l'insertion. Erreur. – infinity

+0

Pourriez-vous expliquer pourquoi vous clonez l'objet entité et enregistrez le clone? Vous avez peut-être déjà essayé cela, mais si vous faites SaveOrUpdate() dans tous vos threads pour le même objet entité (pas de clones), alors quel thread insère en premier, les autres feront des mises à jour. Est-ce que cela fonctionne pour votre conception? –

0

Vous devez mettre une sorte de logique de type "Attendre l'insertion pour terminer" avant d'appeler la mise à jour. C'est une programmation asynchrone multithread standard.

Il est très possible d'appeler Insertion et Mise à jour en même temps sur le même objet dans un environnement multithread. Vous devez juste vous assurer que le code sous-jacent est assez intelligent pour:

  1. Est-ce que l'insert avant la mise à jour
  2. Attendez que l'insert avant de commencer la mise à jour

Il y a plusieurs façons différentes pour ce faire et aucun d'eux n'est nécessairement meilleur qu'un autre. Vous avez besoin d'un verrou que vous pouvez acquérir, abandonner et attendre.

En outre, ce problème n'a rien à voir avec NHibernate. La programmation multithread est très difficile. Il est préférable d'éviter plusieurs threads si cela est possible car la complexité peut facilement échapper à tout contrôle.

Questions connexes