简体   繁体   English

Hibernate 性能最佳实践?

[英]Hibernate Performance Best Practice?

Im writing a Web application using Hibernate 3.我使用 Hibernate 3 编写 Web 应用程序。

So, after a while i noticed that something was slow.所以,过了一会儿,我注意到有些东西很慢。 So i tested hibernate profiler and found that hibernate will make unreasonably many db-calls for simple operation.所以我测试了 hibernate profiler,发现 hibernate 会为简单的操作进行不合理的多次数据库调用。 The reason is ofcourse that i load an Object (this object has several "parents") and these "parents" have other "parents".原因当然是我加载了一个对象(这个对象有几个“父母”),而这些“父母”还有其他“父母”。 So basicly hibernate loads them all, even though i just need the basic object.所以基本上休眠加载它们,即使我只需要基本对象。 Ok, so i looked into lazy-loading.好的,所以我研究了延迟加载。 Which lead me into the Lazyloading-exception, because i have a MVC webapp.这让我进入了 Lazyloading-exception,因为我有一个 MVC webapp。

So now i'm a bit confused as to what is my best approach to this.所以现在我有点困惑我最好的方法是什么。 Basicly all I need is to update a single field on an object.基本上我需要的只是更新对象上的单个字段。 I already have the object-key.我已经有了对象键。

Should I: 1. Dig into Lazy-loading.我应该: 1. 深入研究延迟加载。 And then rewrite my app for a open-session-view?然后重写我的应用程序以打开会话视图? 2. Dig into lazy-loading. 2. 深入研究延迟加载。 And then rewrite my dao's to be more specific.然后将我的 dao 重写为更具体。 Eg writing DAO-methods that will return objects instanciated with only whats necessary for each use-case?例如,编写将返回实例化的对象的 DAO 方法,这些对象仅具有每个用例所需的内容? Could be a lot of extra methods... 3. Scratch hibernate and do it myself?可能有很多额外的方法... 3.从头开始休眠并自己做? 4. Cant really think of other solutions right now. 4.现在真的想不出其他解决方案。 Any suggestions?有什么建议么?

What is the best practice?最佳做法是什么?

  • Don't use joins unless really needed.除非真的需要,否则不要使用连接。 They won't allow you to use neither lazy loading, nor using 2nd level cache for associations它们不允许您既不使用延迟加载,也不使用二级缓存进行关联
  • Use lazy="extra" for large collections, it won't retrieve all the elements until you ask it, you can also use size() method for instance without getting elements from DB对大型集合使用 lazy="extra",它不会在您询问之前检索所有元素,您也可以使用 size() 方法,例如无需从 DB 获取元素
  • Use load() method if it's possible since it doesn't issue a select query until it's required.如果可能,请使用 load() 方法,因为它在需要之前不会发出选择查询。 Eg if you have a Book and an Author and you want to associate them together, this will won't issue any selects, only single insert:例如,如果您有 Book 和 Author 并且您想将它们关联在一起,则不会发出任何选择,只会发出单个插入:

     Book b = (Book) session.load(Book.class, bookId); Author a = (Author) session.load(Author.class, authorId); b.setAuthor(a); session.save(b);
  • Use named queries (in your hbm files or in @NamedQuery) so that they are not parsed during each query.使用命名查询(在您的 hbm 文件或 @NamedQuery 中),以便在每次查询期间不会解析它们。 Don't use Criteria API until it's required (it makes impossible to use PreparedStatement cache in this case)在需要之前不要使用 Criteria API(在这种情况下不可能使用 PreparedStatement 缓存)

  • Use OSIV in your web app since it will load data only when/if it's needed在您的 Web 应用程序中使用 OSIV,因为它仅在需要时/如果需要它才会加载数据
  • Use read-only modes for selects-only: session.setReadOnly(object, true) .对仅选择使用只读模式: session.setReadOnly(object, true) This will make Hibernate not to keep an original snapshot of the selected entity in the persistent context for further dirty checks.这将使 Hibernate 不会在持久上下文中保留所选实体的原始快照以进行进一步的脏检查。
  • User 2nd level cache and Query Cache for read-mostly and read-only data.用户二级缓存和查询缓存主要用于读取和只读数据。
  • Use FlushMode.COMMIT instead of AUTO so that Hibernate doesn't issue select before updates, but be ready that this may lead to stale data being written (though Optimistic Locking can help you out).使用 FlushMode.COMMIT 而不是 AUTO,这样 Hibernate 就不会在更新之前发出选择,但要准备好这可能会导致写入过时的数据(尽管乐观锁定可以帮助您)。
  • Take a look at batch fetching (batch-size) in order to select several entities/collections at one time instead of issuing separate queries for each one.看一下批量提取(batch-size),以便一次选择多个实体/集合,而不是为每个实体/集合发出单独的查询。
  • Do queries like 'select new Entity(id, someField) from Entity' in order to retrieve only required fields.执行诸如“从实体中选择新实体(id,someField)”之类的查询,以便仅检索必填字段。 Take a look at result transformers.看看结果转换器。
  • Use batch operations (like delete) if needed如果需要,使用批处理操作(如删除)
  • If you use native queries, specify explicitly what cache regions should be invalidated (by default - all).如果您使用本机查询,请明确指定应使哪些缓存区域无效(默认情况下 - 全部)。
  • Take a look at materialized path and nested sets for tree-like structures.看看树状结构的物化路径和嵌套集。
  • Set c3p0.max_statements in order to enable PreparedStatment cache in the pool and enable the statement cache of your DB if it's switched off by default.设置c3p0.max_statements以启用池中的 PreparedStatment 缓存,并在默认情况下关闭数据库的语句缓存时启用它。
  • Use StatelessSession if it's possible, it overcomes dirty checks, cascading, interceptors, etc.如果可能,请使用 StatelessSession,它可以克服脏检查、级联、拦截器等问题。
  • Do not use pagination ( setMaxResults() , setFirstResult() ) along with queries that contain joins to collections, this will result in all the records pulled from database and pagination will happen in memory by Hibernate.不要将分页( setMaxResults()setFirstResult() )与包含连接到集合的查询一起使用,这将导致从数据库中提取所有记录,并且 Hibernate 将在内存中进行分页。 If you want pagination, ideally you shouldn't use joins.如果你想要分页,理想情况下你不应该使用连接。 If you can't escape it, again - use batch fetching.如果你不能逃脱它,再次 - 使用批量提取。

Actually there are a lot of tricks, but I can't recall more at the moment.其实有很多技巧,但一时想不起来了。

There are many things you can do to speed-up Hibernate performance, like:你可以做很多事情来加速 Hibernate 的性能,比如:

  1. Enabling SQL statement logging so that you can validate all statements and even detect N+1 query problems during testing.启用 SQL 语句日志记录,以便您可以验证所有语句,甚至在测试期间检测 N+1 查询问题。
  2. Database connection management and monitoring using FlexyPool使用 FlexyPool 进行数据库连接管理和监控
  3. JDBC batching to reduce the number of roundtrips needed to submit INSERT, UPDATE, and DELETE statement. JDBC 批处理以减少提交 INSERT、UPDATE 和 DELETE 语句所需的往返次数。
  4. JDBC Statement caching JDBC 语句缓存
  5. JPA identifier optimizers like pooled or pooled-lo JPA 标识符优化器,如 pooled 或 pooled-lo
  6. Choosing compact column types选择紧凑的列类型
  7. Use the right relationships: bidirectional @OneToMany instead of unidirectional one, using @MapsId for @OneToOne , using Set for @ManyToMany使用正确的关系:双向@OneToMany而不是单向关系,对@OneToOne使用@MapsId ,对@ManyToMany使用Set
  8. Using inheritance the right way and preferring SINGLE_TABLE for performance reasons以正确的方式使用继承并出于性能原因更喜欢 SINGLE_TABLE
  9. Minding the Persistence Context size and avoiding long-running transactions注意持久化上下文的大小并避免长时间运行的事务
  10. Using OS caching, DB caching before jumping to the 2nd-level cache which is also useful to off-load the Primary node when doing database replication在跳转到二级缓存之前使用操作系统缓存、数据库缓存,这对于在进行数据库复制时卸载主节点也很有用
  11. Unleash database query capabilities via SQL native queries通过 SQL 本机查询释放数据库查询功能
  12. Split writes among multiple one-to-one entities to [reduce optimistic locking false positives and get a better chance to hit the database cache even when modifying certain entities.在多个一对一实体之间拆分写入以[减少乐观锁定误报并获得更好的机会,即使在修改某些实体时也能命中数据库缓存。

I believe you want to review this section in the Hibernate manual .我相信您想查看Hibernate 手册中的这一部分

I expect that your original problem of "...unreasonably many db-calls..." is an instance of what they call the "N+1 selects problem".我希望您的原始问题“......不合理的许多 db-calls......”是他们所谓的“N+1 选择问题”的一个实例。 If so, they've got options on how to deal with it.如果是这样,他们可以选择如何处理。

  1. Make the fetch type Join.使提取类型加入。 Then you'll have a single select with several joins, assuming no intermediate collections.然后,假设没有中间集合,您将有一个带有多个连接的选择。
  2. Do lazy loading.做懒加载。
  3. Probably some others, eg FetchProfiles which I've got no experience with.可能还有其他一些,例如我没有经验的 FetchProfiles。

The first two can be specified at the association level, and fetch type can be overridden at the query level.前两个可以在关联级别指定,获取类型可以在查询级别覆盖。 You should be able to get your query to do only what you need, no more, and do it with a 'good' SQL query with these tools.您应该能够让您的查询仅执行您需要的操作,而不是更多,并使用这些工具通过“良好”的 SQL 查询来执行此操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM