4

私は Grails 2.5.1 を使用しています。サービス メソッドを呼び出すコントローラーがあり、StaleObjectStateException. サービス メソッドのコードにobj.save()は、例外を無視するだけの呼び出しの周りに try キャッチがあります。ただし、これらの競合のいずれかが発生するたびに、ログにエラーが出力され、クライアントにエラーが返されます。

私の GameController コード:

def finish(String gameId) {
   def model = [:]
   Game game = gameService.findById(gameId)

   // some other work

   // this line is where the exception points to - NOT a line in GameService:
   model.game = GameSummaryView.fromGame(gameService.scoreGame(game))

   withFormat {
     json {
        render(model as JSON)
     }
   }
}

私の GameService コード:

Game scoreGame(Game game) {
   game.rounds.each { Round round ->
      // some other work
         try {
             scoreRound(round)
             if (round.save()) {
                 updated = true
             }
         } catch (StaleObjectStateException ignore) {
             // ignore and retry
         }
   }
}

スタック トレースは、私のメソッドから例外が生成されたことを示しGameController.finishていますが、それは私のメソッド内のコードを指していませんGameService.scoreGame。これは、オブジェクトの保存/更新が試行されたときではなく、トランザクションが開始されたときに Grails が古さをチェックすることを意味しますか?

私はこの例外に何度も遭遇しましたが、通常はオブジェクト グラフをトラバースしないことで修正します。

たとえば、この場合、game.rounds参照を削除して次のように置き換えます。

def rounds = Round.findAllByGameId(game.id)
rounds.each {
   // ....
}

しかし、それは、トランザクションが作成されたときに古さがチェックされないことを意味し、それは常に実用的であるとは限らず、私の意見では、Grails の遅延コレクションの目的を無効にします。すべての関連付けを自分で管理したい場合は、そうします。

Pessimistic and Optimistic Lockingに関するドキュメントを読みましたが、コードはそこの例に従います。

Grails (GORM) が古さをチェックする方法/タイミング、およびそれを処理する場所について詳しく知りたいですか?

4

1 に答える 1

3

トランザクション構成を示したり説明したりしていませんが、おそらくそれが混乱の原因です。あなたが見ているものに基づいて@Transactional、コントローラーに注釈があると思います。その場合、トランザクションがそこで開始され、(サービスがトランザクションであると仮定して) サービス メソッドが現在のトランザクションに参加するためです。

呼び出すサービスではsave()、セッションをフラッシュしません。特にワークフローの別の部分で他の変更を行う場合は、パフォーマンスが向上します。一度にすべての変更をプッシュできる場合、各オブジェクトに 2 つ以上の更新セットをプッシュしたくないでしょう。フラッシュせず、コントローラーがトランザクションを開始しなかった場合のようにメソッドの最後にトランザクションがコミットされないため、更新はコントローラーメソッドが終了してトランザクションがコミットされたときにのみプッシュされます。

すべてのトランザクション (およびビジネス) ロジックをサービスに移動し、コントローラーからトランザクションのすべての痕跡を削除することをお勧めします。パフォーマンスに影響を与えるつもりがない限り、熱心にフラッシュしてこれを「修正」することは避けてください。

古さのチェックについては、かなり単純です。Hibernate が変更を行うための SQL を生成するとき、その形式はUPDATE tablename SET col1=?, col2=?, ..., colN=? where id=? and version=?. ID は明らかに一致しますが、バージョンが増加している場合、where 句のバージョン部分は一致せず、JDBC の更新カウントは 1 ではなく 0 になります。データの読み取りと更新。

于 2015-09-21T00:46:29.643 に答える