Hibernate 新手休眠一级缓存混乱

Hibernate 新手休眠一级缓存混乱,hibernate,Hibernate,我正在努力对付hibernate。有点困惑 我只是想看一下一级缓存的操作,我知道它可以批量查询,直到会话结束 但是如果我创建了一个对象,hibernate会立即保存它,这样当我以后在同一事务中更新它时,它也必须进行更新: Session session = factory.getCurrentSession(); session.beginTransaction(); Test1 test1 = new Test1(); test1.setName("Test 1"); test1.setVa

我正在努力对付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文档中没有找到任何东西,但我很容易就错过了


谢谢

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

新实例化的 考虑持久类 短暂的冬眠。我们可以打个电话 临时实例持久化 将其与会话关联:

DomesticCat fritz = new DomesticCat();
fritz.setColor(Color.GINGER);
fritz.setSex('M');
fritz.setName("Fritz");
Long generatedId = (Long) sess.save(fritz);
如果
Cat
具有生成的标识符, 生成标识符并 启用
save()
时分配给
cat
打电话。如果
Cat
具有指定的 标识符,或复合密钥 应将标识符分配给 调用前的
cat
实例
save()
。您还可以使用
persist()
而不是
save()
,使用 早期EJB3中定义的语义 草稿

  • persist()
    使临时实例持久化。然而,确实如此 不保证标识符 值将被分配给 持久实例立即 分配可能发生在刷新时间。
    persist()
    还保证 不会执行
    INSERT
    语句 如果在事务外部调用 边界。这在某些情况下很有用 与 扩展会话/持久性上下文
  • save()
    保证返回标识符。 如果必须插入
    
    执行以获取标识符(例如。
    “标识”生成器,而非“序列”),
    此
    插入
    立即发生
    , 不管你在里面还是外面 交易的一部分。这是有问题的 在与一位 扩展会话/持久性上下文
顺便说一句,如果仔细查看
save()
方法,您会注意到它确实返回
Serializable
(分配的标识符)


现在,关于您问题的更新版本,Hibernates使用了一个将DML操作作为会话事务性写后语义的一部分进行排队的方法。DML操作在此排队,直到刷新强制对数据库执行它们为止

调用
save()
persist()
时,包含要插入的实体值副本的插入操作将添加到“插入”列表中

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

这将导致两个DML操作(一个
插入
和一个
更新


这种行为在的评论中得到了某种解释。它(当然)不是最优的,但这就是当前Hibernate实现的工作方式,我不知道解释Hibernate为什么不执行这种优化的所有细节(我想它没有那么简单)。但是请随意提交一个补丁:)

啊-太好了!谢谢-这就解决了为什么它会马上保存它的问题。我将其从生成改为自己提供id,现在两个sql语句都在最后执行。我仍然有点困惑,如果我提供id,为什么会有两个sql语句。我本以为hibernate可以使用对象中的当前值而不是原始值来运行insert。这样就不需要进行插入和更新。但也许这要求很高?有关于hibernate在这些情况下做什么和不做什么的文档吗?或者我应该看看代码吗?也许他们担心您的数据库包含一个触发器,它在插入时执行某些操作,在更新时执行其他操作。在这种情况下,将通过缓存更新来改变行为?谢谢Cobusve-很可能就是这样。虽然我也看到了对同一个对象的多次更新(记住在每次更新之间调用SaveOrUpdate),但只有对象的最终状态更新到数据库,这意味着任何中间触发器(例如更新所做更新的历史记录表)都不会被触发,所以也许他们不太担心触发器;-)帕斯卡,非常感谢你完整而清晰的回答。我不知道你从哪里找到耐心来回答这样的问题,但我非常感谢:-)布鲁斯,不客气。事实上,在我看来,这远不是一个无趣的问题,我觉得它相当有趣(而且许多人甚至不像你现在这样试图理解事情)。