1

MySQL で Grails 1.3.7 を使用しています。私のアプリケーション サーバーは、ユーザーが実行したクエリの検索結果を記録します。スキーマ (簡略化) は以下で構成されます。

class Query {
    String query
    String user
}

class Document {
    String externalId
    String title
}

class Posting {
    Query query
    Document document
    int rank
}

ユーザーが初めてドキュメントを取得するクエリを実行するたびに、新しいインスタンスを作成します。それ以外の場合は、対応するインスタンスを作成するときに既存のインスタンスを再利用しPostingます。特定の に対して のインスタンスは 1 つだけ Document存在する必要がありますexternalIdが、複数のPostingインスタンスがそれを指すことができます。

複数のユーザーが同じドキュメントを取得するクエリを実行できますが、同時実行の問題が発生します。2 人のユーザーがほぼ同時に同じドキュメントを初めて取得した場合、 を作成しようとする 2 回目の試行はDocument、 での一意制約違反で失敗しexternalIdます。これはいい。悪いことPostingに、複製に関連付けられた新しく作成されたインスタンスDocumentもロールバックされます。保存を再試行する方法を理解するのが難しいため、これは良くありません。

私が思いついた解決策は、Documentを呼び出す同期メソッドを使用してを作成しsave(flush: true)、それが失敗した場合は、データベースからドキュメントを再度読み取ることです。次に、結果のドキュメント (保存または再読み込み) を使用して、Postingインスタンスに入力します。このソリューションは機能しますが、ユーザーが取得した結果を処理するには遅すぎます。パラメータを削除flush: trueするとパフォーマンスは向上しますが、インスタンスが適切に作成されるDocumentPostingは限りません。

この種の更新を実装する正しい方法は何ですか?

明確化

私が実行しているクエリは、一度に 100 件の一致を返します。つまり、ユーザー リクエストごとに 0 Document~ 100 個のインスタンスと 100 個のインスタンスを作成しています。Posting

4

1 に答える 1

1

質問を完全に理解していない可能性があるため、これは少し素朴に聞こえるかもしれません。楽観的ロックでこれを解決できませんでしたか?

あなたの catch ブロックで、2 番目のユーザーがパーティーに遅れて来るユーザーであると仮定すると、ドキュメントの最新バージョンを取得して、2 番目のユーザーの投稿に割り当てることができませんでした。

try {
    def posting = .... 
    posting.save(flush: true)
}
catch (org.springframework.dao.OptimisticLockingFailureException e) {
    def doc = Document.findByExternalId(posting.document.externalId)
    posting.document = doc
    posting.save(flush: true)
    ... 
}
于 2013-06-17T21:04:37.450 に答える