OptimisticLockException avec Ebean / Play

J’ai une application Java Play 2.1.3 utilisant Ebean. Je reçois l’exception OptimisticLockException ci-dessous.

[OptimisticLockException: Data has changed. updated [0] rows sql[update person set name=? where id=? and email=? and name=? and password is null and created=? and deleted is null] bind[null]] 

Je comprends qu’il essaie de me dire que le disque a changé entre le moment où je l’ai lu et celui où j’ai essayé de l’écrire. Mais le seul changement se produit dans cette méthode.

 public void updateFromForm(Map form) throws Exception { this.name = form.get("name")[0]; Ssortingng password = form.get("password")[0]; if (password != null && password.length() != 0) { Ssortingng hash = Password.getSaltedHash(password); this.password = hash; } this.update(); } 

Est-ce que je fais mal? J’ai vu la même logique dans les zentasks. De plus, devrais-je être en mesure de voir les valeurs des variables de liaison?

UPDATE: J’appelle updateFromForm () depuis un contrôleur:

 @RequiresAuthentication(clientName = "FormClient") public static Result updateProfile() throws Exception { final CommonProfile profile = getUserProfile(); Ssortingng email = getEmail(profile); Person p = Person.find.where().eq("email", email).findList().get(0); Map form = request().body().asFormUrlEncoded(); if (p == null) { Person.createFromForm(form); } else { p.updateFromForm(form); } return ok("HI"); } 

Un peu en retard, mais pour votre cas, l’annotation @Version devrait être la solution. Nous l’utilisons principalement avec java.util.Date , il peut donc également être utilisé pour déterminer la date de la dernière mise à jour de l’enregistrement, dans le modèle Play qui ne contient que:

 @Version public java.util.Date version; 

Dans ce cas, l’instruction de mise à jour se fera uniquement avec les champs id et version , ce qui est particulièrement utile lors de l’utilisation de modèles volumineux:

 update person set name='Bob' where id=1 and version='2014-03-03 22:07:35'; 

Remarque: vous n’avez pas besoin / devriez mettre à jour ce champ manuellement à chaque sauvegarde, Ebean le fait lui-même. version valeur de version change UNIQUEMENT lorsqu’il y avait des données mises à jour (utiliser obj.update() sans modification de champ de version )

J’ai une approche alternative à cela, où j’ajoute l’annotation

 @EntityConcurrencyMode(ConcurrencyMode.NONE) 

à la classe d’entité.

Ceci désactive la vérification de modification concurrente optimiste avec locking, ce qui signifie que le SQL

 update person set name=? where id=? 

Ceci est encore plus optimiste car il écrase tout changement intermédiaire.

Mystère résolu.

Premièrement, cette annonce de service public. “OptimisticLockException” est un grand seau. Si vous essayez de retrouver l’un de ces objectives, laissez-vous aller à l’idée que cela pourrait vraiment être n’importe quoi.

J’ai résolu mon problème en vidant SQL dans le journal et en trouvant ceci:

 update person set name='Bob' where id=1 and email='[email protected]' and name='Robert' and password is null and created=2013-12-01 and deleted is null 

Donc, je suppose que ce qui se passe quand vous faites une mise à jour, c’est qu’elle crée une clause WHERE avec toutes les entités connues et leurs valeurs telles qu’elles étaient prêtes à l’origine.

Cela signifie que si une autre partie de votre code ou un autre processus modifie quelque chose derrière votre dos, cette requête échouera. J’ai supposé à tort que le problème était que, d’une manière ou d’une autre, .setName (‘Bob’) avait changé le nom dans la firebase database ou dans un cache d’objects.

En réalité, la clause WHERE contient une date, tandis que ma firebase database contient un horodatage complet avec la date, l’heure et le fuseau horaire.

Pour l’instant, je l’ai corrigé en commentant simplement l’horodatage dans le modèle jusqu’à ce que je puisse déterminer si / comment Ebean peut gérer ce type de données.

J’ai eu le même problème, après des heures de recherche, j’ai trouvé la raison. Il s’agissait d’une incohérence du type de parameters dans la firebase database (dans ma chaîne de cas) et de l’object que j’avais créé et essayé de sauvegarder -java.util.Date.

après avoir modifié la firebase database pour contenir l’object datetime, le problème a été résolu