0

我有两个实体XY定义如下。Y与 具有多对一关系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")。然而,在提交之后,我看到数据库中的 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。为了让 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);
}
...
}
4

3 回答 3

1

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

于 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 有一个一级缓存(Session),一旦在一级缓存中加载了某个实体,每次获取到该实体的引用时,都会从一级缓存中取出值。

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

于 2012-05-09T07:29:42.173 回答