18

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

所以,过了一会儿,我注意到有些东西很慢。所以我测试了hibernate profiler,发现hibernate会为简单的操作进行不合理的许多db调用。原因当然是我加载了一个对象(这个对象有几个“父母”),而这些“父母”还有其他“父母”。所以基本上休眠会加载它们,即使我只需要基本对象。好的,所以我研究了延迟加载。这导致我进入延迟加载异常,因为我有一个 MVC webapp。

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

我应该: 1. 深入研究延迟加载。然后重写我的应用程序以获得开放会话视图?2. 深入研究延迟加载。然后重写我的道更具体。例如,编写 DAO 方法将返回实例化的对象,这些对象只包含每个用例所需的内容?可能是很多额外的方法... 3. 从头开始​​休眠并自己做?4. 现在真的想不出其他解决方案。有什么建议么?

最佳做法是什么?

4

3 回答 3

30
  • 除非真的需要,否则不要使用连接。它们不允许您既不使用延迟加载,也不使用二级缓存进行关联
  • 对大型集合使用lazy="extra",在您询问之前它不会检索所有元素,您也可以使用 size() 方法例如而不从数据库中获取元素
  • 如果可能,请使用 load() 方法,因为它在需要之前不会发出选择查询。例如,如果您有 Book 和 Author 并且您想将它们关联在一起,这将不会发出任何选择,只有单个插入:

    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,但要做好准备,这可能会导致写入过时的数据(尽管 Optimistic Locking 可以帮助您)。
  • 看一下批量获取(批量大小),以便一次选择多个实体/集合,而不是为每个实体/集合发出单独的查询。
  • 执行诸如“从实体中选择新实体(id,someField)”之类的查询,以便仅检索必填字段。看看结果转换器。
  • 如果需要,使用批处理操作(如删除)
  • 如果您使用本机查询,请明确指定应使哪些缓存区域无效(默认情况下 - 全部)。
  • 看一下树状结构的物化路径和嵌套集。
  • 设置c3p0.max_statements以便在池中启用 PreparedStatment 缓存,并在默认情况下关闭数据库的语句缓存。
  • 如果可能,请使用 StatelessSession,它可以克服脏检查、级联、拦截器等。
  • 不要将分页(setMaxResults(), setFirstResult())与包含集合连接的查询一起使用,这将导致从数据库中提取所有记录,并且分页将由 Hibernate 在内存中进行。如果你想要分页,理想情况下你不应该使用连接。如果您无法逃脱它,请再次使用批量获取。

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

于 2012-04-25T17:26:13.307 回答
6

您可以做很多事情来加速 Hibernate 性能,例如:

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

我相信您想查看Hibernate 手册中的这一部分

我希望您最初的“...不合理的许多数据库调用...”问题是他们所谓的“N+1 选择问题”的一个实例。如果是这样,他们可以选择如何处理它。

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

前两个可以在关联级别指定,并且可以在查询级别覆盖获取类型。您应该能够让您的查询只做您需要的事情,而不是更多,并使用这些工具通过一个“好的”SQL 查询来完成它。

于 2012-04-25T16:30:45.637 回答