Hibernate性能最佳实践?

20
我正在使用Hibernate 3编写Web应用程序。
过了一段时间,我发现某些操作很慢。因此,我测试了Hibernate分析器,并发现Hibernate会为简单操作进行不合理的数据库调用。原因当然是因为我加载一个对象(该对象有几个“父级”),而这些“父级”有其他“父级”。因此,基本上Hibernate会加载它们所有,即使我只需要基本对象。 好吧,所以我研究了延迟加载。这使我遇到了Lazyloading-exception,因为我有一个MVC WebApp。
现在我有点困惑,不知道最好的方法是什么。 基本上,我只需要更新对象上的单个字段。我已经有了对象键。
我应该: 1. 深入研究延迟加载。然后为开放会话视图重新编写我的应用程序? 2. 深入研究延迟加载。然后重写我的数据访问层(DAO)更具体。例如编写DAO方法,将为每个用例实例化只需要的对象?可能会有很多额外的方法...... 3. 放弃Hibernate自己做? 4. 真的想不出其他解决方案。有任何建议吗?
什么是最佳实践?
3个回答

30
  • 如果不是必要的话,请勿使用join。这既不能使用懒加载,也不能为关联使用二级缓存。
  • 对于大型集合,请使用lazy="extra",它在您请求时才会检索所有元素,您还可以使用size()方法而不必从数据库中获取元素。
  • 如果可能,请使用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缓存无法使用)

  • 在Web应用程序中使用OSIV,因为它只在需要时/如果需要时加载数据
  • 对于仅选择的选项,请使用只读模式:session.setReadOnly(object, true)。这将使Hibernate不会在持久上下文中保留所选实体的原始快照以进行进一步的脏检查。
  • 为只读和大多数读取数据使用第二级缓存和查询缓存。
  • 使用FlushMode.COMMIT而不是AUTO,这样Hibernate在更新之前不会发出select,但要准备好可能会导致写入陈旧数据(尽管乐观锁定可以帮助您解决问题)。
  • 查看批处理获取(batch-size)以一次选择多个实体/集合,而不是为每个实体/集合发出单独的查询。
  • 执行像“select new Entity(id, someField) from Entity”这样的查询,以仅检索所需字段。查看结果转换器。
  • 如果需要,使用批量操作(如删除)
  • 如果使用本地查询,请明确指定应该使缓存区域无效的内容(默认为全部)。
  • 查看材料化路径和嵌套集以用于树状结构。
  • 设置c3p0.max_statements,以启用池中的PreparedStatement缓存并启用您的DB的语句缓存(如果默认情况下关闭)。
  • 如果可能,请使用StatelessSession,它可以克服脏检查、级联、拦截器等问题。
  • 不要在包含对集合进行连接的查询中使用分页(setMaxResults()setFirstResult()),这将导致从数据库中提取所有记录,并且Hibernate将在内存中进行分页。如果要进行分页,则理想情况下不应使用连接。如果无法避免,请再次使用批处理获取。

实际上有很多技巧,但我暂时想不起来更多了。


OSIV,你能解释一下吗?我没听懂。 - Maheshwar Ligade

7

有很多方法可以加速Hibernate性能,例如:

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

1

我相信你想要查看这个Hibernate手册中的章节

我认为你原来的问题“……过多的数据库调用……”是他们所谓的“N+1查询问题”的一个实例。如果是这样,他们有处理它的选项。

  1. 将获取类型设置为Join。然后您将拥有一个带有几个连接的单个选择,假设没有中间集合。
  2. 进行延迟加载。
  3. 可能还有其他一些,例如我没有经验的FetchProfiles。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接