Hibernate:刷新分离的对象 - 奇怪的行为

时间:2013-10-12 14:04:55

标签: java hibernate

我一直在使用Hibernate进行项目,但我对它的实际工作方式还有一些疑问。特别是对持久/分离状态的刷新以及createQuery之间的差异,从会话中获取和加载。

在以下示例中,“groupe”最初处于持久状态,其值已修改但尚未提交

案例#1

// createQuery before evict
// g and groupe point to the same object
Groupe g = (Groupe) session.createQuery("from Groupe as g where g.idGroupe = '" + theid + "'").uniqueResult();
System.out.println("groupe=" + groupe.getTitle()); // modified value
System.out.println("g=" + g.getTitle()); // modified value

session.evict(groupe);
System.out.println("groupe=" + groupe.getTitle()); // modified value
System.out.println("g=" + g.getTitle()); // modified value

session.refresh(groupe);
System.out.println("groupe=" + groupe.getTitle()); // modified value
System.out.println("g=" + g.getTitle()); // modified value

案例#2

// get before evict
// g and groupe point to the same object
Groupe g = (Groupe) session.get(Groupe.class, theid);
System.out.println("groupe=" + groupe.getTitle()); // modified value
System.out.println("g=" + g.getTitle()); // modified value

session.evict(groupe);
System.out.println("groupe=" + groupe.getTitle()); // modified value
System.out.println("g=" + g.getTitle()); // modified value

session.refresh(groupe);
System.out.println("groupe=" + groupe.getTitle()); // value from database
System.out.println("g=" + g.getTitle()); // value from database

案例#3

// load before evict
// g and groupe point to the same object
Groupe g = (Groupe) session.get(Groupe.class, theid);
System.out.println("groupe=" + groupe.getTitle()); // modified value
System.out.println("g=" + g.getTitle()); // modified value

session.evict(groupe);
System.out.println("groupe=" + groupe.getTitle()); // modified value
System.out.println("g=" + g.getTitle()); // modified value

session.refresh(groupe);
System.out.println("groupe=" + groupe.getTitle()); // value from database

System.out.println("g=" + g.getTitle()); // value from database

为什么在使用createQuery进行刷新操作后会出现不同的行为? 这是正常行为吗?如果是,有人可以解释其中的差异吗?

感谢您的帮助。

1 个答案:

答案 0 :(得分:3)

答案很简单:

  • 使用查询会话会话刷新修改。当您evict获得授权时,更改已经保留。
  • 另一方面,通过标识符获取实体不会强制刷新会话。

所有三个案例都在refresh之后显示来自数据库的值。仅在第一种情况下,数据库中的值才是修改后的值


如果您想要这种行为背后的推理:

  • Hibernate无法确定脏实体是否与查询无关。例如,对于已修改的foo属性和查询SELECT entity FROM Entity entity WHERE entity.foo = 'BAR',如果在查询执行之前未刷新更改,则可能会得到不正确的结果。
  • 当你通过标识符获取实体时,Hibernate能够在会话中进行简单的查找并获得正确的实体。无需刷新任何非持久性更改。

希望清楚。