我有两个entites X
和Y
定义如下。 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表已经更改,但是当我再次查询时,我仍然链接到旧版本的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);
}
...
}
答案 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,您仍可能获得实体的旧状态。