简体   繁体   中英

Grails Grom + mongoDb get during save OptimisticLockingException

I try in in grails service save an object in mongodb:

Cover saveCover = new Cover()
saveCover.id = url
saveCover.url = url
saveCover.name = name
saveCover.sku = sku
saveCover.price = price

saveCover.save()

Cover domain looks like this:

class Cover {

    String id
    String name
    String url
    String sku
    String price
}

So I want to have custom id based on url, but during save process I get error:

Could not commit Datastore transaction; nested exception is org.grails.datastore.mapping.core.OptimisticLockingException: The instance was updated by another user while you were editing

But I didn`t use setters and just pass all values in constructor, this exception gone. Why?

As reported in the documentation here:

Note that if you manually assign an identifier, then you will need to use the insert method instead of the save method, otherwise GORM can't work out whether you are trying to achieve an insert or an update

so you need to use insert method instead of save when id generator is assigned

cover.insert(failOnError: true)

if you do not define the mapping like this:

static mapping = {
    id generator: 'assigned'
}

and will use insert method you'll get an auto-generated objectId:

"_id" : "5496e904e4b03b155725ebdb"

This exception occurs when you assign an id to a new model and try to save it because GORM thinks it should be doing an update.

Why this exception occurs

When I ran into this issue I was using 1.3.0 of the grails-mongo plugin. That uses 1.1.9 of the grails datastore core code. I noticed that the exception gets generated on line 847(ish) of NativeEntryEntityPersister . This code updates an existing domain object in the db.

Above that on line 790 is where isUpdate is created which is used to see if it's an update or not. isInsert is false as it is only true when an insert is forced and readObjectIdentifier will return the id that has been assigned to the object so isUpdate will end up evaluating as true.

Fixing the exception

Thanks to && !isInsert on line 791 if you force an insert the insert code will get called and sure enough the exception will go away. However when I did this the assigned id wasn't saved and instead a generated object id was used. I saw that the fix for this was on line 803 where it checks to see if the generator is set to "assigned" .

To fix that you can add the following mapping.

class Cover {
    String id
    String name
    String url
    String sku
    String price
    static mapping = {
        id generator: 'assigned'
    }
}

A side effect of this is that you will always need to assign an id for new Cover domain objects.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM