There doesn't appear to be definite solution to concurrency problems in Grails (2.3.7). I've tried all the recommendations, but when I push the number of concurrent threads, the following piece of code invariably fails:
package simpledb
import grails.transaction.Transactional
import groovy.transform.Synchronized
import org.apache.commons.logging.LogFactory
@Transactional
class OwnerService {
private static final myLock1 = new Object()
private static final myLock2 = new Object()
@Synchronized('myLock1')
static public saveOwner(def ownerName) {
def ownerInstance = null
Owner.withNewTransaction {
ownerInstance = Owner.findOrCreateByName(ownerName)
ownerInstance.save(failOnError: true, flush: true)
}
ownerInstance
}
@Synchronized('myLock2')
static public associateDog(def ownerId, def dogId) {
def lockedOwnerInstance
Owner.withNewTransaction {
lockedOwnerInstance = Owner.lock(ownerId)
def lockedDogInstance = Dog.lock(dogId)
lockedOwnerInstance.addToDogs(lockedDogInstance)
lockedOwnerInstance.save(failOnError: true, flush: true)
}
lockedOwnerInstance
}
}
It fails on the line "def lockedDogInstance = Dog.lock(dogId)":
Error 500: Internal Server Error
URI
/simpledb/JsonSlurper/api
Class
org.hibernate.StaleObjectStateException
Message
Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [simpledb.Dog#111]
The above design is very simple where there's a Many-to-Many relationship between Owner and Dog:
Dog Class:
package simpledb
class Dog {
String name
Breed breed = null
Integer age = null
static hasMany = [owners: Owner]
static belongsTo = Owner
static mapping = { owners lazy: false }
static constraints = {
name blank: false, nullable: false, unique: true
breed nullable: true
age nullable: true
}
}
Owner Class:
package simpledb
class Owner {
String name;
static hasMany = [dogs: Dog]
static mapping = { dogs lazy: false }
static constraints = {
}
}
FYI - The DB is MySQL.
Any recommendations?