JPA:查询子项时未反映父项更改

时间:2012-05-09 06:22:24

标签: java hibernate jpa

我有两个entites XY定义如下。 YX有多对一的关系:

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”)。但是在提交之后,我看到数据库中的X表已经更改,但是当我再次查询时,我仍然链接到旧版本的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.为了让Y知道X已经改变了,我错过了什么?

简而言之,y等于y2,这意味着我的第二个发现是从缓存中检索其信息?

为了让Y知道X已经改变,我错过了什么?

添加输出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);
}
...
}

3 个答案:

答案 0 :(得分:1)

您的每个DAO都有一个EntityManagerFactory和一个EntityManager。我建议你制作EntityManagerFactory static。这样所有实体经理都来自同一家工厂。也许这个问题与二级缓存有关。

答案 1 :(得分:0)

更新记录后使用EntityManager.flush()方法。

以下是flush和refresh方法之间的区别。

      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.

答案 2 :(得分:0)

首先,这是正常和预期的行为。 Hibernate有一级缓存(Session),一旦某个实体加载到第一级缓存中,每次获得对该实体的引用时,都将检索第一级缓存中的值。

您可以通过调用EntityManager.refresh()(或Session.refresh())来刷新缓存中实体的状态。请注意,即使您这样做,如果事务的隔离级别为REPEATABLE_READ,您仍可能获得实体的旧状态。