0

私には2つのエンティティがXあり、次のようにY定義されています。Yと多対1の関係がありXます:

public class X {
    @Id
    @Column(name = "xId", unique = true, nullable = false, length = 50)
    private Integer id;
    @Column(name = "description", nullable = true, length = 50)
    private String description;
    ...
}

public class Y {
    @Id
    @Column(name = "yId", unique = true, nullable = false, length = 50)
    private Integer id;
    @ManyToOne(fetch=FetchType.EAGER)
    @JoinColumn(name="x", nullable=false)
    private X x;
    ...
}

エンティティを更新するXと、ロード時に変更が正しく反映されませんY。Xテーブルに値(1、 "2222")の行がすでにあると仮定します。Yを最初に印刷すると、Xは(1、 "2222")と表示されます。ただし、コミット後、DBのXテーブルが変更されているのがわかりますが、再度クエリを実行すると、Yは古いバージョンのXにリンクされたままになります。

Y y = yDao.findById(ABC);
System.out.println(y);  // y.x.description is "2222"

xDao.beginTransaction();
X x = new X(1, "4444");
xDao.update(x);
xDao.commitTransaction();   

Y y2 = yDao.findById(ABC);  // y.x.description is still "2222" instead of "4444"
System.out.println(y2);

私の結論は、Yが2回目にキャッシュから取得されているということです。Xが変更されたことをYに認識させるために、何が欠けていますか?

つまり、yはy2に等しいので、2番目の検索でキャッシュから情報を取得していますか?

Xが変更されたことをYに認識させるために、何が欠けていますか?

出力SQLの追加:

Hibernate: // first findById()
    select
        y0_.yId as yId12_1_,
        y0_.address as address12_1_,
        y0_.x as x12_1_,
        x1_.xId as xId17_0_,
        x1_.description as descript2_17_0_ 
    from
        daoTest.Y y0_ 
    inner join
        daoTest.X x1_ 
            on y0_.x=x1_.xId 
    where
        y0_.yId=?
Y [id=11, x=X [id=1, description=0000]]   // System.out
Hibernate: // merge(x)
    select
        x0_.xId as xId5_0_,
        x0_.description as descript2_5_0_ 
    from
        daoTest.X x0_ 
    where
        x0_.xId=?
Hibernate: // commitTransaction()
    update
        daoTest.X 
    set
        description=? 
    where
        xId=?
Y [id=11, x=X [id=1, description=0000]]   //System.out, theres no select again

GenericDAOクラス

public class GenericDAOImpl<T, ID extends Serializable> implements
GenericDAO<T, ID> {

private EntityManagerFactory emf = Persistence.createEntityManagerFactory("persistenceUnit");
private EntityManager em = emf.createEntityManager();

protected EntityManager getEntityManager() {
    if (em == null) {
        throw new IllegalStateException(
                "EntityManager has not been set on DAO before usage");           
    } else {        
        return em;
    }
}

public void refresh(T entity) {
    this.getEntityManager().refresh(entity);
}
...
}
4

3 に答える 3

1

各DAOには1つと1つEntityManagerFactoryありますEntityManager。を作成することをお勧めしますEntityManagerFactory static。このように、すべてのエンティティマネージャーは同じ工場から来ています。おそらく、問題は第2レベルのキャッシュに関連しています。

于 2012-05-09T07:56:05.580 に答える
0

レコードを更新した後、EntityManager.flush()メソッドを使用します。

フラッシュ方式とリフレッシュ方式の違いは次のとおりです。

      entityManager.flush();
// Calling this flush method will synchronize the database with the values
// taken from the entity object.

     entityManager.refresh();
// The refresh() method will refresh the entity object with the values taken from the database.
// All the updates that are done are lost.
于 2012-05-09T07:24:59.337 に答える
0

まず第一に、これは正常で予想される動作です。Hibernateには第1レベルのキャッシュ(セッション)があり、一部のエンティティが第1レベルのキャッシュに読み込まれると、このエンティティへの参照を取得するたびに、第1レベルのキャッシュから値が取得されます。

EntityManager.refresh()(またはSession.refresh())を呼び出すことにより、キャッシュ内のエンティティの状態を更新できます。これを行っても、トランザクションの分離レベルがREPEATABLE_READの場合は、エンティティの古い状態を取得する可能性があることに注意してください。

于 2012-05-09T07:29:42.173 に答える