5
votes

I have the following

def save(ACommand command){
  ...
}

@Validateable
class ACommand implements Serializable
{
  ADomainObject bundleDef
}

but every time save is called the version is incremented. So if I open up two browsers and submit a different value in succession, instead of getting an error the second time as I would expect, the value is updated.

I also tried using two different sessions with no difference

Update

If I use breakpoints and submit before the other one is completed it works fine. However, If I let the first complete then submit the second without a refresh the version is updated to the newer one (which I don't want) and the change goes through.

Update 2

When you perform updates Hibernate will automatically check the version property against the version column in the database and if they differ will throw a StaleObjectException. This will roll back the transaction if one is active.

per Grails this should work seems to me.

2
could you show the save implemenation, to see how the optimistic locking case is handled in the controller? otherwise the code snippet does not make much sense, thx :) - Mario David
I am using the auto locking in Grails not sure what you want to see? It just saves an object from a form pretty basic stuff - Jackie

2 Answers

0
votes

AFAIK, you need to check the version and handle failures yourself - it doesn't happen automatically. You can do this with code like this:

/**
 * 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
}

you can call isStale from an action like this

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

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

    // object is not stale, so update it
}
0
votes

I am not sure what you expect to happen but what you describe sounds correct to me unless you have code in your save() action that is relevant.

You can't expect Hibernate to do anything special here. When your save() action is invoked the instance is retrieved using Hibernate, mutated and then saved. That is all fine as far as Hibernate is concerned.

One way to deal with this is when the form for editing the entity is rendered, render the version of the entity that is being edited to a hidden form field which will be submitted when the entity is saved. In the save action after retrieving the entity from the database compare its version to the version retrieved from the hidden form field and if they don't match you know that the entity was modified between those 2 steps and you can react however is appropriate for your app. Note that since your example is using a command object, data binding is being imposed on the entity before your code ever executes. If that isn't what you want, don't use a command object.

I hope that helps.