2013-09-05 2 views
1

Скажем, у меня есть следующий класс домена:Hibernate OptimisticLockingFailureException не бросает, когда он должен

class Book { 
    String name 
    // more properties here, but name is the only one relevant for this example 
} 

Я хотел бы обновить его имя с помощью зрения. Я использую следующую форму, чтобы обновить его:

<g:form action="updateName" id="${book.id}"> 
    <g:hiddenField name="version"/> 
    <g:textField name="name"/> 
    ... 
</g:form> 

В контроллере я использую следующую логику:

def updateName() { 
    println("IN UPDATENAME()") 
    def book = Book.get(params.id) 
    println("VERSION BEFORE ASSIGN: ${book.version}) 
    book.version = params.long('version') 
    println("VERSION AFTER ASSIGN: ${book.version}) 
    book.name = params.name 
    book.save(flush: true) 
    ... 
} 

Я тестирование, открыв ту же страницу редактирования в 2 разные браузеры. Я делаю updateName в одном браузере, а затем другой. Второй updateName должен бросать OptimisticLockingFailureException, но это не так.

Я активировал выход SQL и это то, что я получаю в журналах:

IN UPDATENAME() 
VERSION BEFORE ASSIGN: 0 
VERSION AFTER ASSIGN: 0 
update book set version=?, name=? where id=? and version=? 
binding parameter [1] as [BIGINT] - 1 
binding parameter [2] as [STRING] - 'abc123' 
binding parameter [3] as [BIGINT] - 1 
binding parameter [4] as [BIGINT] - 0 

IN UPDATENAME() 
VERSION BEFORE ASSIGN: 1 
VERSION AFTER ASSIGN: 0 
update book set version=?, name=? where id=? and version=? 
binding parameter [1] as [BIGINT] - 1 
binding parameter [2] as [STRING] - 'def456' 
binding parameter [3] as [BIGINT] - 1 
binding parameter [4] as [BIGINT] - 1 

Другими словами, во втором вызове, я был в состоянии успешно назначить версию от 1 до 0, который должен иметь вызвало исключение, но по какой-то причине SQL-вызов по-прежнему неверно проверяет версию = 1 вместо 0. Кто-нибудь знает, почему это происходит?

+0

Вы также можете показать класс домена 'Книга'? 'version' в неявном свойстве persistence (например,' id'), предоставленном GORM, который обновляется при успешном 'flush'? Мне просто интересно, почему вы используете код плиты котла для обновления версии? – dmahapatro

+0

@dmahapatro: намерение в ручном режиме установки (я полагаю), чтобы убедиться, что Hibernate проверяет версию, отображаемую в браузере. – Thilo

+0

Да, это было намерение. Способ, которым Grails делает это в контроллере подкладок, - это ручная проверка, но вызов 'save()' должен также генерировать исключение, а это не так. –

ответ

0

version - это свойство (а не поле) класса домена, которое фактически определено как метод доступа getVersion(). No setter для version определен в DefaultGrailsDomainClass.

В случае контроллера леса также нет места, где version свойство устанавливается вручную, хотя проверка/проверка выполняется вручную. Оптимистическая блокировка обрабатывается спящим режимом во время сеанса flush, когда он встречается с несоответствием в версии, а несоответствие происходит только в том случае, если второй пользователь является жертвой грязного чтения.

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