4

Hibernate 4.0を使用すると、3つのHibernateエンティティがあります。

歌、カバーアート、カバーイメージ

曲は音楽ファイルを表し、CoverImageは画像を表し、CoverArtはCoverImageを曲に関連付けるために使用されます。曲には複数のカバー画像を含めることができます。

SongとCoverArtには、Hibernateによって自動的に生成された主キーがあります。ただし、Cover Imageの主キーは手動で行われ、画像データのMessageDigestとして作成されます。これを行うのは、同じ画像を多くの曲で使用でき、同じ画像の個別のインスタンスをデータベースに複数回保存したくないためです。また、データベースでファイルを確認できるデータからキーを作成できるためです。存在し、存在する場合は、新しいCoverImageを作成するのではなく、それを取得します。

問題は、私のアプリケーションがマルチスレッドであり、Hibernateが実際にデータベースにすぐにコミットしないため、スレッド1は、カバーイメージがデータベースに既に存在するかどうかを確認し、存在しないことを確認して、新しいSong、CoverArt、およびCoverImageオブジェクトを構築する場合があります。しかし、データがデータベースにコミットされるまでに、CoverImageが別のスレッドによって追加された可能性があるため、新しいCoverImageが既存のCoverImageと同じキーを持っているため、例外が発生します。

私は使用しています

session.merge(coverImage);

だから私はそれでこれを処理できると思いましたが、それは役に立たないようです

4

2 に答える 2

4

失敗したトランザクションを再試行する以外に、この状況を処理する信頼できる方法はありません。

そのため、主キーの制約違反が原因でトランザクションのロールバックが発生した場合は、トランザクションが既に存在するCoverImageと仮定して、トランザクションを再試行する必要があります。Hibernate の例外は回復できないため、これを行うにはCoverImagenew が必要であることに注意してください。Session

merge()この問題は、トランザクション分離セマンティクスに原因があるため、処理できません。最新のMVCCベースの DBMS では、各トランザクションがデータベースの独自のスナップショットを参照します。そのため、並行トランザクションはスナップショットに競合する変更を加えることができます (ただし、同じレコードに変更を加えることはできないため、これらの変更はばらばらでなければなりません)。このような競合は、コミット中に DBMS によってのみ検出され、制約が発生する場合にのみ検出されます。あなたの場合のように違反します(制約の競合がなければ気付かれません。書き込みスキューの異常を参照してください)。

トランザクション内で動作するためmerge()、スナップショットで他のトランザクションが何を行っているかを確認できないため、この問題を克服できません。

于 2012-04-16T13:16:39.033 に答える
1

もう 1 つのオプションは、coverImages のラッパーを使用することです。たとえば。CoverImageWrapper. CoverImageWrapper には、messageDigest 以外の uuId ベースの独自のキーがあります。このクラスは、CoverImage と 1 対 1 でリンクされています。

データベースに格納する際、この CoverImageWrapper キーは常にアプリケーションによって生成されるため、このようにして、アプリケーションによって生成された 3 つのキー (Song、CoverArt、および CoverImageWrapper) をすべて取得し、すべてのスレッドで一意になります。したがって、この方法で重複キーの例外を回避できます。

于 2012-04-16T15:24:07.660 に答える