Hibernate性能最佳实践?

use*_*237 15 java performance orm hibernate jpa

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

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

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

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

什么是最佳做法?

Sta*_*sev 26

  • 除非确实需要,否则不要使用连接.它们不允许您既不使用延迟加载,也不允许使用二级缓存进行关联
  • 对大型集合使用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);
    
    Run Code Online (Sandbox Code Playgroud)
  • 使用命名查询(在您的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在内存中发生.如果你想分页,理想情况下你不应该使用连接.如果你再也无法逃避它 - 使用批量提取.

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


Vla*_*cea 5

正如我在本文或《高性能JavaPersistence》一书中所解释的那样,您可以执行许多操作来提高Hibernate性能,例如:

  1. 启用S​​QL语句日志记录,以便您可以验证所有语句,甚至可以在测试过程中检测到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. 使用OS缓存,可在跳转到第二级缓存之前进行数据库缓存,这对于在执行数据库复制时减轻主节点的负载也很有用
  11. 通过SQL本机查询释放数据库查询功能
  12. 在多个一对一实体之间进行拆分写入,以减少乐观的锁定误报,即使在修改某些实体时,也有更好的机会访问数据库缓存。