2016-03-01 23 views
1

似乎并没有明确的解决方案来解决Grails(2.3.7)中的并发问题。我已经尝试了所有的建议,但是当我推的并发线程数,下面这段代码总是失败:Grails“Row被其他事务更新或删除(或未保存值映射不正确)”

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

它未能就行了“高清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的是。

有什么建议吗?

回答

1

好的,这里有很多事情要做,其中大部分我敢打赌你可以处置。因此,我们不要试图解决它,让我们把它降到最低限度,并从那里开始:

  1. 您的服务方法不应该是静态的。
  2. 您的服务已经成交,所以withNewTransaction()可以去。你也不需要冲洗。
  3. 没有必要同步服务方法。
  4. 您不需要锁定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 
    } 
} 

看多远,带你。你甚至可以删除所有者锁。

+0

谢谢@ Emmanuel-Rosa的回应。我做了你推荐的改变(这是我开始的)。但是,我继续获得与前面列出的相同的错误消息。与上面列出的代码中的偶尔线程相比,这次多线程会出现此错误。 不知何故,当涉及到并发数据库修改时,Grails无法按记录工作。 –

+0

你的应用程序是什么使得多线程可以尝试更新相同的域模型? –

+0

应用程序本质上接受带有JSON负载的REST请求并将它们保存在数据库中。但是,在创建记录之前,我们需要检查数据是否已经存在,在这种情况下需要更新数据。我使用JMeter来测试代码,因为它允许模拟多线程调用。 –

相关问题