Hibernate性能最佳实践?

时间:2012-04-25 15:52:44

标签: java performance hibernate jpa orm

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

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

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

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

最佳做法是什么?

3 个答案:

答案 0 :(得分:26)

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

    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)”等查询,以便仅检索必填字段。看看结果变形金刚。
  • 如果需要,使用批处理操作(如删除)
  • 如果使用本机查询,请明确指定应使无效的缓存区域(默认情况下为全部)。
  • 查看物化路径和树状结构的嵌套集。
  • 设置c3p0.max_statements以启用池中的PreparedStatment缓存,并在默认情况下关闭数据库时启用数据库的语句缓存。
  • 如果可能的话,使用StatelessSession,它可以克服脏检查,级联,拦截器等。
  • 不要使用分页(setMaxResults()setFirstResult())以及包含联接到集合的查询,这将导致从数据库中提取的所有记录和分页将由Hibernate在内存中发生。如果你想分页,理想情况下你不应该使用连接。如果你再也无法逃避它 - 请使用批量提取。

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

答案 1 :(得分:5)

正如我在this article或我的High-Performance JavaPersistence book中所解释的那样,您可以采取许多措施来加速Hibernate的性能,例如:

  1. Enabling SQL statement logging,以便您可以验证所有语句甚至detect N+1 query problems during testing
  2. 使用FlexyPool
  3. 进行数据库连接管理和监控
  4. JDBC batching减少提交INSERT,UPDATE和DELETE语句所需的往返次数。
  5. JDBC Statement caching
  6. JPA标识符优化器,例如pooled or pooled-lo
  7. 选择紧凑的列类型
  8. 使用正确的关系:bidirectional @OneToMany instead of unidirectional one,使用@MapsId for @OneToOneusing Set for @ManyToMany
  9. 使用inheritance the right waypreferring SINGLE_TABLE for performance reasons
  10. Minding the Persistence Context size and avoiding long-running transactions
  11. 在跳转到二级缓存之前使用操作系统缓存,数据库缓存,这对于在进行数据库复制时卸载主节点也很有用
  12. 通过SQL native queries
  13. 释放数据库查询功能
  14. 将多个一对一实体之间的分割写入reduce optimistic locking false positives,即使修改某些实体,也可以更好地命中数据库缓存。

答案 2 :(得分:1)

我相信您要查看此section in the Hibernate manual

我希望您的原始问题“......无理的多次db调用...”是他们称之为“N + 1选择问题”的实例。如果是这样,他们就可以选择如何处理它。

  1. 使获取类型加入。假设没有中间集合,那么你将有一个带有多个连接的选择。
  2. 懒加载。
  3. 可能是其他一些人,例如我没有经验的FetchProfiles。
  4. 可以在关联级别指定前两个,并且可以在查询级别覆盖提取类型。您应该能够让您的查询只执行您需要的操作,而不是更多,并使用这些工具进行“良好”的SQL查询。