新手hibernate一级缓存混乱

时间:2010-05-27 14:20:04

标签: hibernate

我只是想要熟悉hibernate。有点困惑。

我只想观看第一级缓存的操作,我理解这种操作会批量查询直到会话结束。

但是如果我创建一个对象,hibernate会立即保存它,所以当我稍后在同一个事务中更新它时,它也必须进行更新:

Session session = factory.getCurrentSession();
session.beginTransaction();

Test1 test1 = new Test1();
test1.setName("Test 1");
test1.setValue(10);
// Touch it
session.save(test1);

System.out.println("At checkpoint 1");

test1.setValue(20);

session.getTransaction().commit();

我看到用于保存的sql,然后是'在检查点1',然后是用于更新的sql。我有没有设置错误或者我误解了hibernate的第一级缓存?在第一级缓存上是否有一个很好的文档 - 我在hibernate文档中没有找到任何内容,但我很容易错过它..

谢谢!

1 个答案:

答案 0 :(得分:2)

对于问题的第一个版本,您可以在文档的10.2. Making objects persistent章中找到一些答案:

  

a的新实例化实例   考虑持久性类   Hibernate瞬态。我们可以做一个   瞬态实例持久化   将其与会话相关联:

DomesticCat fritz = new DomesticCat();
fritz.setColor(Color.GINGER);
fritz.setSex('M');
fritz.setName("Fritz");
Long generatedId = (Long) sess.save(fritz);
     

如果Cat有生成的标识符,   生成标识符   在cat时分配给save()   调用。如果Cat已分配   标识符,或复合键,   标识符应该分配给   调用之前的cat实例   save()。您也可以使用persist()   而不是save(),而不是persist()   早期在EJB3中定义的语义   。草案

     
      
  • persist()使瞬态实例持久化。但是,确实如此   不保证标识符   值将被分配给   持久化实例立即,   分配可能在刷新时发生。   INSERT也保证了它   不会执行save()语句   如果在交易之外调用它   边界。这很有用   与...长期对话   扩展的会话/持久化上下文。
  •   
  • INSERT确保返回标识符。   如果必须是INSERT   执行以获得标识符(例如   “身份”发生器,而不是“序列”),   这个save()会立即发生,   无论你是在里面还是外面   交易这是有问题的   与...进行长时间的对话   扩展的会话/持久化上下文。
  •   

顺便说一句,如果仔细查看Serializable方法,您会注意到它确实返回了save()(指定的标识符)。


现在,关于问题的更新版本,Hibernates使用ActionQueue 保存排队的DML操作,作为会话的事务写入后写语义的一部分。 DML操作在这里排队,直到刷新强制它们对数据库执行。

当您致电persist()INSERT时,包含要插入的实体值的副本的插入操作会添加到“插入”列表中。

然后,您修改持久性实体,并在刷新时将实体检测为脏,并为该实体的值的另一个副本添加另一个操作(更新操作) :未使用新值更新挂起的插入操作。

这导致两个DML操作(UPDATE和{{1}})。

HHH-2588的评论以某种方式解释了这种行为。它(当然)不是最佳的,但这是当前Hibernate实现的工作方式,我不知道所有细节来解释为什么Hibernate不执行这种优化(我猜它不是那么简单)。但随意提交补丁:)