1

私はそれを理解するために一晩中過ごしました、そして私はこの時点で必死です。Grails2.1.0プロジェクトにサービスクラスがあります。Webサービスに対してクエリを実行します-クエリはスレッド化されます。スレッドがデータを取得すると、synchronizedメソッドWriteToDBを呼び出します。メソッドは名前(String field)を取り、。を介してドメインをチェックしますfindByName。レコードが存在する場合は、他に何もせずに新しいレコードを作成します。

今私はチェックしました、そしてメソッドは確かに一度に呼び出されるのに1つのスレッドだけを許可します、これはログサンプルです:

エラー2013-01-0221:29:47,408[スレッド-21]エラー-WriteToDBSTART

エラー2013-01-0221:29:47,474[スレッド-21]エラー-WriteToDBが終了しました

エラー2013-01-0221:29:47,475[スレッド-20]エラー-WriteToDBSTART

エラー2013-01-0221:29:47,571[スレッド-20]エラー-WriteToDBが終了しました

エラー2013-01-0221:29:47,581[スレッド-49]エラー-WriteToDBSTART

エラー2013-01-0221:29:47,866[スレッド-49]エラー-WriteToDBが終了しました

エラー2013-01-0221:29:47,867[スレッド-45]エラー-WriteToDBSTART

エラー2013-01-0221:29:48,202[スレッド-45]エラー-WriteToDBが終了しました

エラー2013-01-0221:29:48,203[スレッド-48]エラー-WriteToDBSTART

エラー2013-01-0221:29:48,320[スレッド-48]エラー-WriteToDBが終了しました

ただし、レコードが重複しています!!! 新しいレコードを保存するたびにflush:true、それを実行します。なぜそれが起こり続けるのか分かりませんか?手動でテストしました。テストの前に1つの既知のレコードをDBに追加しましたが、複製されることはありませんでしたが、保存されている新しいレコードは最大6回複製されます。

助けてください。何かにインデックスを付ける必要がありますか?または、特別な方法で何かをフラッシュしますか?なぜそれが起こっているのですか?

[2013年2月1日更新]

レコードを保存するために使用しているコードは次のとおりです。

      if(!f) { // Check if record doesn't exist then save, else nothing
          f = new Feature(name: featureName)
          if( !f.save(flush: true) ) {
              f.errors.each {
                  log.error it
              }
          }
      }

また、エラーサンプル:

エラー2013-01-0222:25:58,868[スレッド-20]エラーutil.JDBCExceptionReporter-キー「名前」のエントリ「自動送信」が重複しています

エラー2013-01-0222:25:58,873 [スレッド-20]エラーhibernate.AssertionFailure-アサーションエラーが発生しました(これはHibernateのバグを示している可能性がありますが、セッションの安全でない使用が原因である可能性が高いです)メッセージ:null id Project2.Featureエントリ内(例外が発生した後にセッションをフラッシュしないでください)

私はこのように解釈することができます(コードの「保存」部分の前にFindByNameを取得しました):レコードを検索し、それが存在しないため、作成しています。重複エントリについて文句を言い、変数「f」に対してnullを取得しています後でリレーションとして別のテーブルに挿入します。

私はtrycatchブロックでこのコードを修正しようとするかもしれないと思います...アイデア?

4

2 に答える 2

3

さて、いくつかのテストと調査の後、私は問題を見つけました。

Domain.save(flush:true)-スレッドが原因で機能しませんでした。

これが私のスレッド作成の例です:

Thread.start {
    Domain.withTransaction {
         // Doing stuff and calling synchronization method to write data to DB
    }
}

ここで修正が見つかりました:Grails、GPars、およびデータの永続性

に置き換えDomain.withTransactionましたDomain.withNewSession

Thread.start {
    Domain.withNewSession {
         // Doing stuff and calling synchronization method to write data to DB
    }
}

そしてsave(flush: true)mySQLへの書き込みを開始します。データはmySQLに書き込まれるため、findBy ...は適切な結果を返し始めます。したがって、アプリケーションは重複したレコードを作成しようとしなくなります。問題が解決しました!

ありがとう、Jinzhao Wu、あなたの提案は大いに役立ちました!

于 2013-01-06T05:52:30.697 に答える
2

簡単な解決策は次のとおりです。追加するだけです

static constraints = {
    name unique: true
}

ドメインクラスに移動し、で有効性を確認する代わりに、サービスメソッドで関連する例外をキャッチしますfindByName

または、重複の理由を見つけるために、サービスメソッドからコードを投稿する必要がある場合があります。

于 2013-01-03T03:02:15.840 に答える