Версия Grails 2.3.7 Optimistic Locking обновляется каждый раз при отправке объекта Command.

у меня есть следующее

def save(ACommand command){
  ...
}

@Validateable
class ACommand implements Serializable
{
  ADomainObject bundleDef
}

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

Я также пытался использовать два разных сеанса без разницы

Обновить

Если я использую точки останова и отправляю до завершения другого, все работает нормально. Однако, если я позволю первому завершиться, а затем отправлю второе без обновления, версия будет обновлена ​​​​до более новой (чего я не хочу), и изменение будет выполнено.

Обновление 2

Когда вы выполняете обновления, Hibernate автоматически сверяет свойство версии со столбцом версии в базе данных и, если они различаются, генерирует исключение StaleObjectException. Это приведет к откату транзакции, если она активна.

для Grails мне кажется, это должно работать.


person Jackie    schedule 23.04.2014    source источник
comment
Не могли бы вы показать реализацию сохранения, чтобы увидеть, как оптимистичная блокировка обрабатывается в контроллере? в противном случае фрагмент кода не имеет особого смысла, спасибо :)   -  person Mario David    schedule 23.04.2014
comment
Я использую автоматическую блокировку в Grails. Не знаю, что вы хотите увидеть? Он просто сохраняет объект из формы довольно простой вещи   -  person Jackie    schedule 23.04.2014


Ответы (2)


Насколько я знаю, вам нужно самостоятельно проверять версию и обрабатывать сбои - это не происходит автоматически. Вы можете сделать это с помощью такого кода:

/**
 * Returns a boolean indicating whether the object is stale
 */
protected boolean isStale(persistedObj, versionParam = params.version) {

    if (versionParam) {
        def version = versionParam.toLong()
        if (persistedObj.version > version) {
            return true
        }
    } else {
        log.warn "No version param found for ${persistedObj.getClass()}"
    }
    false
}

вы можете вызвать isStale из такого действия

def update() {
    Competition competition = Competition.get(params.id)

    if (isStale(competition)) {
        // handle stale object
        return
    }

    // object is not stale, so update it
}
person Dónal    schedule 23.04.2014
comment
2 проблемы, которые у меня есть с этим ответом. 1.) Это не работает со сценарием и командным объектом (как я показал), потому что при сериализации он должен где-то получить, поэтому встроенная версия, которую я получаю, выше, чем должна быть, что означает, что версия persistedObj.version › всегда правда. Если я не сделаю это с точкой останова, то вышеизложенное работает нормально. 2.) Я думал, что вся идея оптимистической блокировки в Grails заключалась в том, чтобы предотвратить создание такого типа ручного кода? - person Jackie; 23.04.2014
comment
1) если объект не устарел, то версия, отправленная в параметрах, должна == версия в базе данных 2) Насколько я знаю, вам нужно проверить версию самостоятельно, это не происходит автоматически. Если вы посмотрите на исходный код каркасного контроллера, вы увидите код, похожий на приведенный выше. - person Dónal; 23.04.2014
comment
на самом деле мне пришлось добавить тег myVersion в GSP, чтобы сохранить его. В противном случае он автоматически увеличивался до более высокой версии. сравнение свойства непостоянной версии с сохраненным помогло мне определить, устарело ли оно. - person Jackie; 23.04.2014

Я не уверен, что вы ожидаете, но то, что вы описываете, звучит правильно для меня, если у вас нет соответствующего кода в вашем действии save().

Вы не можете ожидать, что Hibernate сделает здесь что-то особенное. Когда вызывается ваше действие save(), экземпляр извлекается с помощью Hibernate, видоизменяется и затем сохраняется. Это все хорошо, что касается Hibernate.

Один из способов справиться с этим — когда форма для редактирования объекта визуализируется, отображать версию редактируемого объекта в скрытом поле формы, которое будет отправлено при сохранении объекта. В действии сохранения после извлечения объекта из базы данных сравните его версию с версией, полученной из скрытого поля формы, и если они не совпадают, вы знаете, что объект был изменен между этими двумя шагами, и вы можете реагировать, однако это подходит для вашего приложение. Обратите внимание, что, поскольку в вашем примере используется командный объект, привязка данных накладывается на объект еще до того, как ваш код будет выполнен. Если это не то, что вам нужно, не используйте командный объект.

Надеюсь, это поможет.

person Jeff Scott Brown    schedule 23.04.2014
comment
С точки зрения командного объекта. Существует ли более простая форма сериализатора/десериализатора NvP для объектов домена в экосистеме? - person Jackie; 25.04.2014
comment
@ Джеки, я не уверен, о чем ты спрашиваешь. Вы можете очень легко сериализовать в/из JSON. Это то, что вы ищете? - person Jeff Scott Brown; 25.04.2014
comment
RT, но составные формы возвращаются в виде пар имя-значение, поэтому сериализация в JSON ничего для меня не дает, пока не поддерживается отправка форм json. - person Jackie; 25.04.2014
comment
Поддерживаются формы JSON. - person Jeff Scott Brown; 25.04.2014
comment
Хорошо, я думал, что они еще не реализованы, но я могу изучить это. - person Jackie; 25.04.2014