Hibernate性能最佳实践?

我正在使用Hibernate 3编写Web应用程序。

所以,过了一会儿我注意到事情很慢。 所以我测试了hibernate profiler,发现hibernate会为简单的操作做出无理的多次db调用。 原因是我加载一个Object(这个对象有几个“父母”),这些“父母”有其他“父母”。 所以基本上hibernate会加载它们,即使我只需要基本对象。 好的,所以我看着懒加载。 这导致我进入Lazyloading-exception,因为我有一个MVC webapp。

所以现在我有点困惑,我最好的方法是什么。 基本上我只需要更新对象上的单个字段。 我已经拥有了对象键。

我应该:1。进入延迟加载。 然后重写我的应用程序以获得开放会话视图? 2.挖掘延迟加载。 然后重写我的dao更具体。 例如,编写DAO方法,这些方法将返回仅与每个用例所必需的内容相关联的对象? 可能是很多额外的方法…… 3.从头开始hibernate并自己做吗? 4.现在真的不能想到其他解决方案。 有什么建议么?

什么是最佳做法?

  • 除非确实需要,否则不要使用连接。 它们不允许您既不使用延迟加载,也不允许使用二级缓存进行关联
  • 对大型集合使用lazy =“extra”,在你提出它之前它不会检索所有元素,你也可以使用size()方法而不需要从DB获取元素
  • 如果可能,请使用load()方法,因为在需要之前它不会发出select查询。 例如,如果你有一本书和一个作者,并且你想将它们关联在一起,这将不会发出任何选择,只有一个插入:

    Book b = (Book) session.load(Book.class, bookId); Author a = (Author) session.load(Author.class, authorId); b.setAuthor(a); session.save(b); 
  • 使用命名查询(在您的hbm文件或@NamedQuery中),以便在每次查询期间不解析它们。 在需要之前不要使用Criteria API(在这种情况下无法使用PreparedStatement缓存)

  • 在您的网络应用程序中使用OSIV,因为只有在需要时才会加载数据
  • 将只读模式用于仅选择: session.setReadOnly(object, true) 。 这将使Hibernate不在持久化上下文中保留所选实体的原始快照,以进行进一步的脏检查。
  • 用户二级缓存和查询缓存,用于读取主要和只读数据。
  • 使用FlushMode.COMMIT而不是AUTO,以便Hibernate在更新之前不会发出select,但是请准备好这可能导致写入过时的数据(尽管乐观锁定可以帮助你)。
  • 查看批量提取(批量大小),以便一次选择多个实体/集合,而不是为每个实体/集合发出单独的查询。
  • 执行“从实体中选择新实体(id,someField)”等查询,以便仅检索必填字段。 看看结果变形金刚。
  • 如果需要,使用批处理操作(如删除)
  • 如果使用本机查询,请明确指定应使无效的缓存区域(默认情况下为all)。
  • 看一下物化路径和树状结构的嵌套集。
  • 设置c3p0.max_statements以在池中启用PreparedStatment缓存,并在默认情况下关闭数据库时启用其语句缓存。
  • 如果可能的话,使用StatelessSession,它可以克服脏检查,级联,拦截等。
  • 不要使用分页( setMaxResults()setFirstResult() )以及包含对集合的连接的查询,这将导致从数据库中提取的所有记录和分页将由Hibernate在内存中发生。 如果你想要分页,理想情况下你不应该使用连接。 如果你再也无法逃避它 – 使用批量提取。

实际上有很多技巧,但我现在想不起更多。

正如我在本文或我的高性能JavaPersistence书中所解释的那样,您可以采取许多措施来加速Hibernate性能,例如:

  1. 启用S​​QL语句日志记录,以便您可以validation所有语句,甚至可以在测试期间检测N + 1查询问题 。
  2. 使用FlexyPool进行数据库连接管理和监视
  3. JDBC批处理可减少提交INSERT,UPDATE和DELETE语句所需的往返次数。
  4. JDBC语句缓存
  5. JPA标识符优化器,如池化或池化
  6. 选择紧凑的列类型
  7. 使用正确的关系: 双向@OneToMany而不是单向关系,使用@MapsId@OneToOne , 使用Set for @ManyToMany
  8. 以正确的方式使用inheritance,并且出于性能原因而更喜欢SINGLE_TABLE
  9. 注意持久性上下文大小并避免长时间运行的事务
  10. 在跳转到二级缓存之前使用操作系统缓存,数据库缓存,这对于在执行数据库复制时卸载主节点也很有用
  11. 通过SQL本机查询释放数据库查询function
  12. 拆分在多个一对一实体之间写入,以减少乐观锁定误报,并且即使在修改某些实体时也可以更好地命中数据库缓存。

我相信你想在Hibernate手册中查看这一节 。

我希望你的原始问题“……无理的多次db调用…”是他们所谓的“N + 1选择问题”的一个例子。 如果是这样,他们就可以选择如何处理它。

  1. 使获取类型加入。 假设没有中间集合,那么你将有一个带有多个连接的选择。
  2. 懒加载。
  3. 可能还有一些其他的,比如我没有经验的FetchProfiles。

前两个可以在关联级别指定,并且可以在查询级别覆盖提取类型。 您应该能够让您的查询只执行您需要的操作,而不是更多,并使用这些工具进行“良好”的SQL查询。