我只是想要熟悉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文档中没有找到任何内容,但我很容易错过它..
谢谢!
答案 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不执行这种优化(我猜它不是那么简单)。但随意提交补丁:)