Spring Optimistic Locking: Comment réessayer la méthode transactionnelle jusqu'à la validation du commit
J'utilise Spring 2.5 et Hibernate JPA mise en oeuvre avec Java et "conteneur" gérer les Transactions.
J'ai un "après que l'utilisateur est s'engager" la méthode qui met à jour les données en arrière-plan et doivent être engagée indépendamment de ConcurrencyFailureException
ou StaleObjectStateException
exception, car il ne sera jamais montré au client. En d'autres termes, la nécessité de rendre Optimiste Verrouillage Pessimiste. (Qui pourrait se produire si les méthodes d'exécution est de prendre un peu plus longtemps et quelqu'un a modifié des données dans d'autres transactions)
J'ai lu beaucoup de choses sur la quantité des choses, réessayer exception dans recherche pour DEFAULT_MAX_RETRIES ou 6.2.7. Exemple ou chapitre 14.5. Réessayer. J'ai aussi trouvé dans stackoverflow ici et ici.
J'ai essayé ceci:
public aspect RetryOnConcurrencyExceptionAspect {
private static final int DEFAULT_MAX_RETRIES = 20;
private int maxRetries = DEFAULT_MAX_RETRIES;
Object around(): execution( * * (..) ) && @annotation(RetryOnConcurrencyException) && @annotation(Transactional) {
int numAttempts = 0;
RuntimeException failureException = null;
do {
numAttempts++;
try {
return proceed();
}
catch( OptimisticLockingFailureException ex ) {
failureException = ex;
}
catch(ConcurrencyFailureException ex) {
failureException = ex;
}
catch( StaleObjectStateException ex) {
failureException = ex;
}
} while( numAttempts <= this.maxRetries );
throw failureException;
}
}
RetryOnConcurrencyException
est mon Annotation pour marquer les méthodes qui doivent être retentée, si une exception atteint son apogée. N'a pas fonctionné... j'ai aussi essayé de plusieurs façons, comme SELECT ... FOR UPDATE
EntityManager.lock(...)
Quelle est la meilleure façon d'éviter de données obsolètes, sale lit etc. cette stratégie avec le Printemps? Réessayer?, la synchronisation?, APP lock?, l'isolement?, sélectionner ... pour la mise à jour? Je ne pouvais pas le faire fonctionner et je suis vraiment heureux sur toute aide.
Voici le pseudo-code que j'aime faire:
void doSomething(itemId) {
select something into A;
select anotherthing into B;
//XXX
item = getItemFormDB( itemId ); //takes long for one user and for other concurrent user it could take less time
item.setA(A);
item.setB(B);
//YYYY
update item;
}
Entre //XXX //YYY une autre session peut modifier l'élément, puis le StaleObjectStateException est lancée.
source d'informationauteur knarf1983
Vous devez vous connecter pour publier un commentaire.
J'ai une solution mais je pense que c'est laid. J'attrape tous les RuntimeException et il ne fonctionne que pour de nouvelles transactions. Savez-vous comment faire mieux? Voyez-vous des problèmes?
Tout d'abord, j'ai fait une Annotation:
Puis j'ai fait un intercepteur comme ceci:
Printemps applicationConfig.xml:
Et une méthode annotée comme ceci:
Utilisation Printemps Réessayer pour recommencer toute la méthode lorsque un numéro de version ou d'horodatage échec de la vérification (optimiste de verrouillage se produit).
Configuration
Utilisation
De configuration du projet
Printemps application de Démarrage est valide défini printemps tentatives de version, de sorte que seul ce qui est demandé:
Nous avons et ce que nous faisons est:
Sur StaleObjectStateException, préciser l'action de la file d'attente
et réessayez à partir de #2
Nous avons une nouvelle tentative de contre de re-jeter l'exception de la fin.
REMARQUE: Ce n'est pas officiellement pris en charge la méthode (Hibernate stipule clairement qu'une session qui a jeté une exception doit être jeté et ne pas ré-utilisé), mais c'est une solution connue (avec la limitation que vous ne pouvez pas supprimer de façon sélective à l'action de mise à jour, mais doit effacer l'ensemble de la file d'attente).
Jeter une autre option ici: BoneCP (http://jolbox.com) a l'appui automatiquement réessayer transactions en cas d'échec (y compris lors de la DB va vers le bas, le réseau tombe en panne, etc).