Question

Let's say I have the following domain class:

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

I'd like to update its name via a view. I'm using the following form to update it:

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

In the controller, I'm using the following logic:

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)
    ...
}

I'm testing it by opening the same edit page in 2 different browsers. I do updateName in one browser, followed by the other one. The second updateName should be throwing an OptimisticLockingFailureException, but it's not.

I enabled SQL output and this is what I get in the logs:

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

In other words, in the second call, I was able to successfully assign the version from 1 to 0, which should have caused the exception, but for some reason, the SQL call still checks incorrectly for version = 1 instead of 0. Does anybody know why this is happening?

Was it helpful?

Solution

version is a property (and not a field) of Domain Class which is actually defined as an accessor method getVersion(). No setter for version is defined in DefaultGrailsDomainClass.

In case of scaffolded controller as well, there is no where version property is set manually, although the check/validation is done manually. Optimistic Locking is handled by hibernate during session flush when it comes across a mismatch in version, and the mismatch only happens if the second user is a victim of a dirty read.

In your case, either you have to harvest the scaffolded controller logic by manually validating the version or you have to rely on Hibernate to do its job instead of manipulating the version manually which is not feasible.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top