Grails" Row被另一个事务更新或删除(或未保存的值映射不正确)"

时间:2016-03-01 21:53:36

标签: multithreading grails gorm database-concurrency

对于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。

有什么建议吗?

2 个答案:

答案 0 :(得分:1)

好的,你在这里有很多事情,其中​​大部分我打赌你可以处理掉。因此,不要试图修复它,而是将其拆解到最低限度并从那里开始:

  1. 您的服务方式不应该是静态的。
  2. 您的服务已经是交易性的,因此withNewTransaction()可以使用。你也不需要冲洗。
  3. 无需同步服务方法。
  4. 您不需要锁定Dog,因为您没有更改它(将其添加到Owner.dogs只会在联接表中创建一条记录)。
  5. 通过这些更改,您的服务最终会如下所示:

    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。