2013-12-02 5 views
10

У меня есть приложение 2.1.3 Java Java, использующее Ebean. Я получаю исключение OptimisticLockException ниже.OptimisticLockException с Ebean/Play

[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"); 
} 
+0

Не могли бы вы включить метод, в котором вы вызываете 'updateFromForm'? – mantithetical

+0

Хорошо, я обновил его. Я вызываю updateFromForm() внутри контроллера. updateFromForm сам определяется в модели. Знаете ли вы, я должен увидеть значения для переменных привязки в своем сообщении об ошибке или нет? Спасибо за любую помощь. – latj

ответ

8

Немного поздно, но для вашего случая @Version аннотация должна быть решением. Мы используем его в основном с java.util.Date, поэтому он может быть использован также для определения даты последнего изменения записи в Play модели, просто:

@Version 
public java.util.Date version; 

В такой постановке случае обновление будет сделано с id и version поля только - полезно, особенно при использовании с большими моделями:

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

Примечание: вам не нужно/необходимо обновить это поле вручную при каждом сохранить, Ebean делает это сам. version значение изменяется лишь при наличии обновленных данных (так, используя obj.update(), где ничего не меняется, не обновляют version поле)

+0

Его никогда не поздно. Фактически, я сталкиваюсь с той же проблемой сейчас в другом проекте. Когда я пытаюсь добавить (at) Version к свойству (строка, заполненная uuid), она говорит: «Ошибка чтения аннотаций для моделей. МоеМодель». Является ли (at) Version новой или устаревшей? Спасибо за понимание. – latj

+1

Нет, он не является старым или обесценившимся, может попытаться использовать полный путь '@ javax.persistence.Version', иначе создайте новый вопрос и покажите нам свою модель. – biesior

4

Тайна решена.

First- это публичное объявление об услугах. «OptimisticLockException» - большое ведро. Если вы пытаетесь отследить один из них, будьте готовы к идее, что это действительно может быть что угодно.

Я понял мою проблему сброса SQL в журнал и найти это:

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 

Так что я думаю, что происходит, когда вы делаете обновление является то, что он строит ИНЕКЕ со всеми известными организациями и их поскольку они были изначально готовы.

Это означает, что если какая-либо другая часть вашего кода или другого процесса что-то изменит за вашей спиной, этот запрос не удастся. Я ошибочно предположил, что проблема в том, что каким-то образом .setName («Bob») изменило имя в БД или кеше объектов.

Действительно, дело в том, что предложение WHERE включает дату, в то время как моя база данных содержит целую метку времени с датой, временем и часовым поясом.

На данный момент я исправил его, просто комментируя временную метку в модели, пока не смогу выяснить, может ли Ebean обрабатывать этот тип данных.

+0

Спасибо! У меня была аналогичная проблема, связанная с установкой даты с помощью ручной вставки с помощью функции postgres now(). Оказывается, дата postgres отличается от даты Ebean. – duxx0r

0

У меня была такая же проблема, после нескольких часов поиска я нашел причину .. Это было несогласованности тип параметров в базе данных (в моей строке ввода) и объект, который я создал, и попытался сохранить -java.util.Date.

после изменения базы данных для хранения даты и времени объекта проблема была решена

15

У меня есть альтернативный подход к этому, когда я добавить аннотацию

@EntityConcurrencyMode(ConcurrencyMode.NONE) 

к классу сущностей.

Это отключает Оптимистическую блокировку одновременной проверки модификации, означающую SQL становится

update person set name=? where id=? 

Это еще более оптимистичны, так как он просто перезаписывает любые промежуточные изменения.

+0

в каком пакете есть аннотация @EntityConcurrencyMode? – Peace

+0

упаковка com.avaje.ebean.annotation; –