第 2 レベルのキャッシュに MySQL、Hibernate (3.5.1-Final)、および EHcache(1.2.3) を使用する Java アプリケーションがあります。
hibernate.properties 分離レベルは Read-committed 分離 = 2 です。
# 2-Read committed isolation
hibernate.connection.isolation=2
多数の同時トランザクションの下で、ロード時に特定のコレクション (DB 関連付け) が ObjectNotFoundException をスローし、第 2 レベルのキャッシュがそのコレクションの古いコピーを返しているように見えるという問題が発生しています。
このコレクションにアクセスする (読み取りのみ) さまざまな種類のトランザクションがあり、そこから項目を追加/削除するトランザクションは 2 つだけです。
この問題は、単一のトランザクション ロードまたは中程度のトランザクション ロード (10 ~ 20 の同時接続) では見られません。
たとえば、 Character エンティティがあります。
@Entity
@Table(name = "CHARACTERS")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Character extends AbstractCharacter implements Serializable {
...
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@OneToMany(mappedBy = "character", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<CharacterItem> items;
エンティティが含まれているコレクションからエンティティを削除し、session.delete() を呼び出すことで、エンティティを削除するときにオブジェクト グラフを適切に維持しています。
character.getItems().remove(characterItem);
session.delete(characterItem);
セット項目を変更してみました。CacheConcurrencyStrategy から:
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<CharacterItem> items;
に
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Set<CharacterItem> items;
運がない。
データベース ロックは使用せず、代わりに楽観的同時実行制御を使用して、競合するトランザクションをキャッチして再試行します。
この時点で確認できる解決策は次の 2 つだけです。
ObjectNotFoundExceptionをキャッチして、コレクションをインテリジェントに削除しようとします (ただし、例外には十分なコンテキストがないようです)。
アイテム コレクションで@NotFound(action=NotFoundAction.IGNORE)アノテーションを使用します。これにより、ObjectNotFoundException は無視され、スローされません (ただし、これが第 2 レベルのキャッシュでどのように機能し、適切なデータが参照されているかについては懸念があります)。 .
@NotFound(action=NotFoundAction.EVICT_2ND_LEVEL_CACHE_RELOAD) があれば、そのオブジェクトをキャッシュから追い出し、コレクションをリロードしようとします。
FetchyType を LAZY から EAGER に変更することもできますが、問題を理解し、トランザクションのデータが高い並行性の下で一貫していることを提供する最適なソリューションを選択したいと考えています。