1

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

参考までに - DB は MySQL です。

推奨事項はありますか?

4

2 に答える 2

1

OK、あなたはここで多くのことを行っていますが、そのほとんどはあなたが処分できるに違いありません。したがって、修正しようとする代わりに、最小限に分解して、そこから先に進みましょう。

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

それがあなたをどこまで連れて行くか見てください。所有者ロックを解除できる場合もあります。

于 2016-03-02T03:25:24.083 に答える