Comment verrouiller les objets avant de les mettre à jour à l'aide de NHibernate modes de verrouillage?
Donc d'abord permettez-moi de préciser ce que j'essaie d'accomplir. J'ai une table qui est rempli avec des emplois. Et il y a un service web avec une méthode qui permet la modification des données de la tâche appelée SaveJob
. Cette méthode récupère le travail et toutes ses données, exécute des validations (qui nécessitent certaines requêtes db de leur propre à d'autres tables) sur les nouvelles données, puis l'enregistre dans la base de données. C'est un peu lent. Environ une seconde.
Ce qui se passe parfois deux SaveJob
appels seront effectués à proximité sur le même travail et ils vont courir les uns sur les autres. Actuellement c'est le seul serveur web, mais je voudrais avoir ma solution web de batterie compatible, donc même si je suis conscient de la façon de résoudre ce problème à l'aide d'un singleton, je préfère avoir les serrures géré par la base de données.
La question est puis-je utiliser NHibernate et base de données SQL Server serrures pour obtenir une deuxième SaveJob appel à bloc quand il essaie de lire un Travail qui est déjà en cours de modification par un autre SaveJob appel?
Je crois que la réponse est oui, mais je ne suis pas vraiment sûr de savoir comment aller à ce sujet. J'ai lu la documentation sur le ISession.Lock()
et je crois que ce dont j'ai besoin est d'utiliser le NHibernate.LockMode.Upgrade
Ma prochaine question est de savoir quand est-ce verrou libérée?
Je suppose qu'il est libéré lorsque la transaction est validée, mais je ne trouve pas la documentation qui l'affirme explicitement.
Cependant, si c'est le cas, alors il est un moyen pour moi d'ouvrir une autre transaction et exécutez des requêtes sans la clôture de la transaction, j'ai commencé lorsque j'ai attrapé le travail en premier lieu? Ou dois-je ont à faire tout cela en une seule transaction?
OriginalL'auteur Spencer Ruport | 2013-08-21
Vous devez vous connecter pour publier un commentaire.
Tout d'abord, je vous déconseillons d'utiliser une seule opération sur plusieurs threads depuis le ISession lui-même n'est pas thread-safe.
Lorsque vous utilisez
LockMode.Upgrade
sur la session, ou sursession.Get()
, NHibernate émettra unselect with (rowlock)
déclaration de la (des détails peuvent dépendre du type de base de données et de configuration) lorsque vous récupérez de l'entité. Si l'objet a été précédemment récupérés par un autre thread, le thread courant va attendre jusqu'à ce que le verrou est libéré ou à l'expiration du délai. La serrure en elle-même est communiqué lors de laupdate
instruction est exécutée surtransaction.Commit()
. À l'aide deLockMode.UpgradeNoWait
offre une fonctionnalité similaire, sauf qu'il n'attend pas et simplement échoue lorsque le verrou est pris.Ce Ayende post a aussi quelques infos sur ce SQL NHibernate émet sur
session.Lock()
.Vous pouvez lire sur les différents types de serrures sur le NHibernate Documentation Chapitre 11, Section 6.
Tout d'abord, la mise à jour devrait se faire en une seule opération, ce qui comprend l'obtention de l'objet, mise à jour des propriétés et de l'appel de mise à jour, ou alternativement, vous pouvez l'appeler
session.Merge()
sur le détachement de l'entité. Dans tous les cas, vous n'avez pas besoin de plusieurs opérations de ce. La validation si, je le ferais, même avant d'essayer de mettre à jour une entité comme il semble inefficace pour attraper un objet que pour la nouvelle mise à jour de la validation échoue.Encore une chose,vous ne devriez pas besoin d'une transaction à valider l'objet, mais dans les deux cas, vous devez le faire dans une transaction précédente, et puis il suffit d'ouvrir une nouvelle session ou la transaction. Vous n'avez pas ces ouverte trop longtemps.
Les validations j'ai à faire sur les données de ce travail nécessitent j'ai fait d'autres bases de recevoir des appels. Certains des validations sont dépendantes des données dans la base de données. Je peux "pousser" une autre transaction ou de démarrer un autre, sans interférer avec le Travail/modification d'une opération sur le même thread?
Vous pouvez ouvrir une transaction pour récupérer les données nécessaires pour la validation, la clôture de la transaction/session, (et comme je l'ai dit, vous n'avez pas besoin d'une opération pour cela, il suffit d'une session, même si certains pourraient vous recommandons d'utiliser les transactions sur les opérations en lecture seule), procéder à la validation puis en ouvrir une autre opération pour sauver la mise à jour.
OriginalL'auteur rae1
Ces travaux pointent sur la même ligne de base de données ou qu'elles sont complètement différentes entités?
S'ils pointent vers une instance de travail, vous pouvez utiliser le verrouillage optimiste à l'aide de
version
d'interdire les données de réécriture.Si elles sont différentes, c'est juste le point de base de données pour permettre simultanés exécution de la requête.
somehow slow
peut être sur table/d'un index/d'identification de verrouillage.Les verrous sont libérés au plus tard après une validation, dépend de l'isolement lavel. Certains (lire) les verrous sont relâchés immédiatement après l'exécution de la requête, les mises à jour dans ligne spécifique peut être libéré après une validation.
EDIT:
Évidemment le verrouillage optimiste n'est pas bon pour vous, vous devez utiliser
http://nhibernate.info/doc/nh/en/index.html#manipulatingdata-update-lock
OriginalL'auteur Martin Podval