对于Grails(2.3.7)中的并发问题,似乎没有明确的解决方案。我已经尝试了所有的建议,但是当我推送并发线程的数量时,下面的代码总是会失败:
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
}
}
它在线路上失败" 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]
如果所有者与狗之间存在多对多关系,上述设计非常简单:
狗类:
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
}
}
所有者类:
package simpledb
class Owner {
String name;
static hasMany = [dogs: Dog]
static mapping = { dogs lazy: false }
static constraints = {
}
}
仅供参考 - 数据库是MySQL。
有什么建议吗?
答案 0 :(得分:1)
好的,你在这里有很多事情,其中大部分我打赌你可以处理掉。因此,不要试图修复它,而是将其拆解到最低限度并从那里开始:
withNewTransaction()
可以使用。你也不需要冲洗。Dog
,因为您没有更改它(将其添加到Owner.dogs
只会在联接表中创建一条记录)。通过这些更改,您的服务最终会如下所示:
package simpledb
import grails.transaction.Transactional
import org.apache.commons.logging.LogFactory
@Transactional
class OwnerService {
def saveOwner(def ownerName) {
def ownerInstance = Owner.findOrCreateByName(ownerName)
ownerInstance.save(failOnError: true)
ownerInstance
}
def associateDog(def ownerId, def dogId) {
def ownerInstance = Owner.lock(ownerId)
def dogInstance = Dog.read(dogId)
ownerInstance.addToDogs(dogInstance)
ownerInstance.save(failOnError: true)
ownerInstance
}
}
看看你走了多远。您甚至可以删除所有者锁定。
答案 1 :(得分:0)
除了@ Emmanuel-Rosa所说的那样,如果同时进行的更新太多,您还可以确保在保存之前调用“刷新”(对所有者)吗? (repeatable reads方法)。
加入表的添加不应该受到这些的影响。仅当试图将某些狗“添加”到同一主人时,才可能引起问题。
另一种方法(在这种情况下不是,但是),如果仅要更新一两列,则可以使用普通SQL。