2

楽観的なトランザクションを実行するためにコントローラーで使用する TransactionService を導入しました。そうすべき

  • 与えられたトランザクションを実行しようとする (= 閉鎖)
  • 失敗した場合はロールバックし、
  • 失敗したらもう一度試す

基本的には次のようになります。

class TransactionService {
  transactional = false // Because withTransaction is used below anyway
  def executeOptimisticTransaction(Closure transaction) {
    def success = false
    while (!success) {
      anyDomainClass.withTransaction { status ->
        try {
          transaction()
          success = true
        } catch(Exception e) {
          status.setRollbackOnly()
        }
      }
    }
  }
}

もう少し複雑です。たとえば、再試行する前に別の Thread.sleeps を使用し、ある段階で中止しますが、ここでは問題ではありません。クロージャーとして安全に実行されるトランザクションを渡すコントローラーから呼び出されます。

私の問題:サービスが同時更新のために org.hibernate.StaleObjectStateException にヒットすると、再試行を続けますが、例外は消えません。

コントローラーから渡されたトランザクションでドメインクラスを再アタッチしたり、サービスまたはコントローラーでセッションをクリアしたりするなど、すでにさまざまなことを試しましたが、役に立ちませんでした。私は何が欠けていますか?

status.createSavepoint() を使用して transaction() が呼び出される前に savePoint を挿入しようとすると、「Transaction Manager はネストされたトランザクションを許可しません」というエラーが発生したことに注意してください。トランザクションがコントローラーからサービスに渡されるためにエラーが存在し、それを回避するために新しい/ネストされたトランザクションを開始する必要があるのではないかと疑ったため、これを試しましたが、エラーが示すように、私の場合は不可能です。

それとも、トランザクションをクロージャーとして渡すことが問題なのでしょうか?

.withTransaction の前に使用されるドメイン クラスは問題ではないと思いますか?

4

1 に答える 1

1

それ自体はクロージャではありませんが、transaction内部に古い変数参照があると思います。実行時にオブジェクトを再読み取りするクロージャーのみを渡そうとするとどうなりますか?好き

executeOptimisticTransaction {
  Something some = Something.get(id)
  some.properties = aMap
  some.save()
}

Hibernateでオブジェクトを再読み取りせずに、オブジェクトを「更新」することは不可能だと思います。

はい、.withTransaction()を呼び出すクラスは関係ありません。

計算された合計/評価を更新する例の場合、それ自体が問題となるデータの重複です。私はどちらかと言えば:

  1. 「ダーティ」フラグに基づいて評価を更新する(Quartz)ジョブを作成します。これにより、更新時間のコストでDBCPUを節約できる可能性があります。
  2. または、SQLまたはHQLで実行します。たとえば、Book.executeQuery('update Rating set rating=xxx')最新の評価を使用します。重い負荷に最適化する場合は、とにかくGroovy-wayのすべてを実行するわけではありません。レーティングオブジェクトをGrailsに保存せず、読み取るだけです。
于 2010-12-07T15:42:48.043 に答える