0

単純化するEntityと、次のようになります。

@Entity
@Table(name = "SOMETABLE")
public class SomeEntity {

    // real code has id and more columns

    @Column(name = "SOMECOLUMN")
    private String someColumn;

    @Transient
    private SomeObject transientObject;

    // getters and setters
}

@NamedQueryDAO メソッドは、および JPA EntityManager(大まかにスタブ化)を使用して、エンティティのリストを読み込みます。

@Transactional
public List<SomeEntity> getSomeEntities() {
    TypedQuery<SomeEntity> query = entityManager.createNamedQuery("findSomeEntities", SomeEntity.class);
    List<SomeEntity> someEntities = query.getResultList();
    for (SomeEntity someEntity : someEntities) {
        someEntity.setTransientObject(<some value here>);
        return someEntities;
    }
}

このメソッドも設定することに注意してくださいtransientObject(コード例では簡略化されています)。

次回getSomeEntities()呼び出されると、まだ設定されているquery.getResultList();オブジェクトのリストが返されます。transientObject一時オブジェクトが null であることを期待しますが、そうではありません。有効な第 1 レベルまたは第 2 レベルのキャッシュはありません。

これをさらに混乱させるために、これは HSQL インメモリ データベースを使用する単体テスト中にのみ発生します。Tomcat サーバーで Web アプリケーションを実行すると、問題なく動作します。

少しデバッグしたところ、セッション キャッシュ(Hibernate では常に有効になっていることを理解しています) では、単体テストを実行すると、以前に読み込まれたすべてのオブジェクトが読み込まれているように見えますが、アプリケーション サーバーで実行すると空でした。これは、休止状態がデータベースではなくキャッシュからオブジェクトをフェッチすることを意味していると思われます。

また、Spring アプリケーションであることも知っておく価値があります。

これの理由は何ですか?または、私の主な問題を言い換えると、HSQLDB を使用してエンティティを 2 回目にロードするときに一時オブジェクトが null にならないのはなぜですか?

4

3 に答える 3

0

一次キャッシュ/セッションキャッシュと関係があるようです。

第 1 レベルのキャッシュは、セッションのコンテキスト内のすべてのオブジェクトを格納し、それを再利用します。これは、トランザクションごとに新しいセッションが開始されるため、アプリケーション サーバーを使用する場合には影響しません。

つまり、DAO メソッドを呼び出すたびに新しいセッションが作成され、これはキャッシュが空であることを意味します。

この問題を解決するには、セッションを閉じて、2 回目の呼び出しの前に新しいセッションを作成してみてください。

2 つの異なるトランザクション内に含めることもできます。これにより、動作する可能性もあります。

編集:マグナスからの質問に答える

本当は別の言い方をするべきだった。各休止状態セッションは、トランザクションの終了時に閉じられます。

Session の Hibernate ドキュメントによると、

セッションのライフサイクルは、論理トランザクションの開始と終了によって制限されます。(長いトランザクションは、複数のデータベース トランザクションにまたがる場合があります。)

アプリケーション サーバーの観点からは、ほとんどの場合 (おそらく実用性のためすべての場合)、複数の物理トランザクションを含む論理トランザクションを識別する方法がありません。

このため、各物理トランザクションを論理トランザクションとして扱います。これは、各物理トランザクションの終了時にセッションが閉じられることを意味します。

Seamの会話スコープと Java EE 6 の新しいスコープのコンテキストでは@ViewScoped、複数の物理トランザクションにまたがる論理トランザクションを識別できることは議論の余地があります。しかし、それほど単純ではないと思いますし、そのように実装されているとは思いません。ただし、どちらにしてもこれを確認する情報はありません。

于 2013-03-19T20:12:46.483 に答える
0

テスト ケースで @Transactional を使用していますか? はいの場合は、それを削除してみてください。

于 2013-03-20T00:06:49.577 に答える
0

これは、常にオンになっている Hibernate の第 1 レベル キャッシュの効果です。第 1 レベルのキャッシュは、次の動作を提供します。

同じ Session から同じ行を 2 回フェッチすると、Session オブジェクトから同じエンティティ インスタンス (つまり、== セマンティクスを使用) が取得されます。

テスト時に getSomeEntities への複数の呼び出しに対して同じセッションを持っているようですが、実行時にはそうではありません。テスト ケースはアプリ コードとは異なる方法で処理されているように思われます。

于 2013-09-13T12:08:51.370 に答える