使 hibernate save() 和 update() 作为单个插入优化

Con*_*D55 5 optimization session hibernate insert save

我想知道如何通过我的 Hibernate (4) & Oracle 设置减少 SQL 更新。

一个简单的案例可能是这样的:

打开一个会话/事务,使用 session.save() 创建一个新实体 Xyz,处理一些业务逻辑,对 Xyz 进行一些更改并调用 session.update(),然后让会话正常关闭,并通过提交到数据库休眠。

提交时,Hibernate 将执行插入操作,然后执行更新 —— 但它真正需要做的只是一次插入操作,但在本例中使用 Xyz的最新属性。

有没有人有做这种事情的任何想法/模式?或者有什么方法可以改变 Hibernate 的行为?或者你对此有什么看法——它是一个完整的反模式吗?

我知道 Hibernate 足够聪明,可以省略多个更新,当一个更新只是覆盖另一个更新时——那么为什么插入不相似呢?

这个小片段可以重现“问题”:

MyEntity e = new MyEntity("xxx"); 
Session session = sessionFactory.openSession(); 
session.beginTransaction();
session.save(e); e.setName("yyy"); 
session.getTransaction().commit(); 
session.close();
Run Code Online (Sandbox Code Playgroud)

顺便说一下,我没有什么可担心的触发因素。

这个例子非常简单,性能问题可能看起来微不足道,但实际上我正在处理一个更复杂的对象(即多次插入和更新),而且数量很大,所以避免更新会很好。

小智 1

有没有一种方法可以将对象添加到会话中,并将其标记为持久性,但直到最后才调用 save() (即不会生成 INSERT)?

如果您想推迟执行Session.persist(Object)直到会话刷新和/或事务关闭,请考虑使用重构。Session.save(Object)INSERT

来自JBoss Hibernate 社区文档的第 10.2 节:

您还可以使用 persist() 代替 save(),其语义在 EJB3 早期草案中定义。

  • persist()使瞬态实例持久化。但是,它不保证标识符值会立即分配给持久化实例,分配可能会在刷新时发生。 还保证如果在事务边界之外调用该语句,persist()则不会执行该语句。INSERT这对于具有扩展会话/持久性上下文的长时间运行的对话非常有用。
  • save()确实保证返回一个标识符。如果INSERT必须执行 an 来获取标识符(例如“身份”生成器,而不是“序列”),则INSERT无论您是在交易内部还是外部,都会立即发生。这在具有扩展会话/持久性上下文的长时间运行对话中是有问题的。

另一个有用的参考可以在本博客文章“将其全部放在一起”部分顶部的方法到场景网格的左上角单元格中找到,该单元描述了从未持久化的对象的行为,如下所示:persist()

  1. 对象作为新实体添加到持久性上下文
  2. 新实体插入到数据库中flush()/commit()