OptimisticLockException с Ebean / Play
У меня есть приложение Play 2.1.3 Java, использующее Ebean. Ниже я получаю исключение OptimisticLockException.
[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]]
Я понимаю, что он пытается сказать мне, что запись изменилась между тем, когда я ее читал, и тем, когда я пытался ее написать. Но единственное изменение происходит в этом методе.
public void updateFromForm(Map<String, String[]> form) throws Exception {
this.name = form.get("name")[0];
String password = form.get("password")[0];
if (password != null && password.length() != 0) {
String hash = Password.getSaltedHash(password);
this.password = hash;
}
this.update();
}
Я делаю это неправильно? Я видел подобную логику в zentasks. Кроме того, должен ли я видеть значения для переменных привязки?
UPDATE: я вызываю updateFromForm () из внутри контроллера:
@RequiresAuthentication(clientName = "FormClient")
public static Result updateProfile() throws Exception {
final CommonProfile profile = getUserProfile();
String email = getEmail(profile);
Person p = Person.find.where().eq("email", email).findList().get(0);
Map<String, String[]> form = request().body().asFormUrlEncoded();
if (p == null) {
Person.createFromForm(form);
} else {
p.updateFromForm(form);
}
return ok("HI");
}
4 ответа:
Немного поздно, но для вашего случая
@Version
аннотация должна быть решением проблемы. Мы используем его в основном сjava.util.Date
, поэтому его можно также использовать и для определения даты последнего обновления записи, в модели воспроизведения это просто:@Version public java.util.Date version;
В таком случае оператор update будет выполняться только с полями
id
иversion
- полезно, особенно при использовании с большими моделями:update person set name='Bob' where id=1 and version='2014-03-03 22:07:35';
Примечание: вам не нужно/не нужно обновлять это поле вручную при каждом сохранении, Ebean делает это сам.
version
значение изменяется только тогда, когда были обновлены данные (поэтому использованиеobj.update()
, где ничего не меняется, не обновляет полеversion
)
У меня есть альтернативный подход к этому, где я добавляю аннотацию
@EntityConcurrencyMode(ConcurrencyMode.NONE)
К классу сущностей.
Это отключает оптимистическую блокировку одновременной проверки модификации, что означает, что SQL становится
Это еще более оптимистично, так как он просто перезаписывает любые промежуточные изменения.update person set name=? where id=?
Тайна решена.
Первое-это публичное служебное объявление. "OptimisticLockException" - это большое ведро. Если вы пытаетесь отследить одного из них, будьте открыты для идеи, что это действительно может быть что угодно.
Я решил свою проблему, сбросив SQL в журнал и обнаружив следующее:
update person set name='Bob' where id=1 and email='jj@test.com' and name='Robert' and password is null and created=2013-12-01 and deleted is null
Итак, я предполагаю, что происходит, когда вы делаете обновление, это то, что он строит предложение WHERE со всеми известными сущностями и их значениями, как они были изначально готовы.
Это означает, что если любая другая часть вашего кода или другой процесс изменяет что-то за вашей спиной, этот запрос не будет выполнен. Я ошибочно предположил, что проблема была в этом как-то .setName ('Bob') изменил имя в БД или каком-то кэше объектов.
На самом деле произошло то, что предложение WHERE включает дату, в то время как моя база данных включает всю метку времени с датой, временем и часовым поясом.
На данный момент я исправил это, просто комментируя метку времени в модели, пока я не смогу выяснить, если / как Ebean может обрабатывать этот тип данных.