2012-05-09 21 views
0

XYという2つのエンティティが次のように定義されています。 YXとの一対一の関係に多く持っている:私は、エンティティXを更新するとJPA:子の照会時に親の変更が反映されない

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; 
    ... 
} 

を私はYをロードする際に、変更が正しく反映されません。 Xテーブルの行はすでに値(1、 "2222")であると仮定します。 Yを最初に印刷すると、Xは(1、 "2222")と表示されます。しかし、私はDBのXテーブルが変更されたが、再び照会するとき、私はまだXの古いバージョンにリンクされているY参照コミット後:

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); 
} 
... 
} 
+1

新しいxオブジェクトをyオブジェクトに割り当てる場所はわかりません。私はあなたが望むものを手に入れないと思う。 – maerch

+0

読み込み時にトランザクションを使用するとどうなりますか? 'y'のマニュアル' EntityManager.refresh'は 'x'を正しく更新しますか? – ewernli

+0

私はそれを照会するときにYが新しい値をX上で選ぶようにします。これは単なる例です。私のポイントは全く別の場所の誰かが更新を行うことができる(x)と私はまだ新しいXに接続されている古いXの値を取得するでしょう – javaNoober

答えて

1

それぞれのDAOにはEntityManagerFactoryEntityManagerの1つがあります。私は、EntityManagerFactorystaticを作ることを提案します。このようにして、すべてのエンティティマネージャは同じ工場から来ます。たぶん、問題は第2レベルのキャッシュに関連しています。

+0

ご協力いただきありがとうございます。はい、問題は2つのDAOを作成するパターン自体であることを確認しました。これは1つの一意のentityManagerで動作し、リフレッシュや何もせずに動作します。 – javaNoober

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. 
+0

トランザクションをコミットすると、トランザクションは自動的に変更をフラッシュします。 SQLログごとに、更新は既に行われています。 – ewernli

0

まず、これは正常な動作です。 Hibernateは第1レベルのキャッシュ(Session)を持ち、あるエンティティが第1レベルのキャッシュにロードされると、このエンティティへの参照を取得するたびに、第1レベルのキャッシュからの値が取得されます。

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

+0

リフレッシュは効果がありません。それぞれのDAOに別個のentityManagerがあるため可能でしょうか? – javaNoober

+0

Xエンティティをリフレッシュしましたか?または単にY? –

+0

私はどちらかと両方をリフレッシュしようとしましたが効果はありません。 – javaNoober

関連する問題