如何优化hibernate?

刚接触HIBERNATE的人可能会遇到性能问题。实现同样的功能,HIBERNATE和JDBC的性能相差十倍以上是正常的。如果不及早调整,很可能会影响整个项目的进度。

通常,HIBERNATE性能调优的主要考虑因素如下:

*数据库设计调整

* HQL优化

* API的正确使用(如根据不同的业务类型选择不同的采集和查询API)

*主要配置参数(日志、查询缓存、fetch_size、batch_size等。)

*映射文件优化(ID生成策略、二级缓存、延迟加载、关联优化)

*一级缓存管理

* L2缓存有许多独特的策略。

*交易控制策略。

1,数据库设计

a)降低关联的复杂性

b)尽量不要使用联合主键。

C) ID生成机制。不同的数据库提供不同的机制。

d)适当冗余数据,不过度追求高范式。

2.HQL优化

如果HQL抛弃了和HIBERNATE本身的一些缓存机制的关联,那么它的优化技巧和普通SQL是一样的,很容易在网上找到一些经验。

3、主要配置

a)查询缓存,不同于下面提到的缓存,是HQL语句的缓存,也就是同一条语句再次执行时可以使用缓存的数据。但查询缓存在一个交易系统中可能会适得其反(数据变化频繁,查询条件相同的概率不大):会白白消耗大量系统资源,却很难派上用场。

B) fetch_size,类似于JDBC参数,参数并不是越大越好,而是要根据业务特点来设置。

C) batch_size同上。

d)在生产系统中,记得关闭SQL语句的打印。

4.隐藏物

a)数据库级缓存:这种级别的缓存是最高效最安全的,但是不同的数据库可以管理不同的级别。例如,在ORACLE中,您可以指定在创建表时将整个表放在缓存中。

b)会话缓存(SESSION cache):在HIBERNATE会话中有效,这一级别的缓存没有侵扰性,大多由HIBERNATE自动管理,但它提供了清除缓存的方法,在大量的添加/更新操作中有效。例如,如果同时添加100,000条记录,并按照正常方式进行,很可能会发现OutofMemeroy异常。此时,您可能需要手动清除此级别的缓存:Session.evict和Session.clear

c)应用缓存:在SESSIONFACTORY中是有效的,所以也是优化的重中之重。所以也考虑了各种策略。在将数据放入这一级别的缓存之前,需要考虑一些先决条件:

I数据不会被第三方修改(例如,是否有另一个应用程序也在修改数据?)

二。数据不会太大。

三。数据不会频繁更新(否则使用缓存可能会适得其反)。

四。数据会被频繁查询。

动词 (verb的缩写)数据不是关键数据(例如,涉及金钱、安全等问题。).

缓存有几种形式,可以在映射文件中配置:只读(read-only,适用于很少变化的静态数据/历史数据)、非严格读非严格读写(一种常见的形式,效率一般)、事务型(JTA,支持较少的缓存产品)。

d)分布式缓存:与c)中的配置相同,只是缓存产品的选择不同,目前HIBERNATE中选择不多。目前大部分项目,如Oscar oscache、jboss cache,对其在集群(尤其是关键交易系统)中的使用持保守态度。在集群环境中,只使用数据库级缓存是最安全的。

5.延迟装载

a)实体的延迟加载:通过使用动态代理来实现。

b)集合延迟加载:HIBERNATE通过实现自己的集合/列表来提供这种支持。

c)延迟加载属性:

6、方法选择

a)为了完成同样的事情,HIBERNATE提供了一些方式可供选择,但是具体使用的方式可能会对性能/代码产生影响。显示一次返回10万条记录(列表/集/包/图等。)很可能导致内存不足的问题,但如果使用基于游标(ScrollableResults)或迭代器的结果集,就不存在这个问题。

b)会话的load/get方法,前者会使用二级缓存,而后者不会。

c)查询和列表/迭代器。如果你仔细研究它们,你可能会发现许多有趣的情况。它们之间的主要区别是(如果使用Spring,find find、iterator方法在HibernateTemplate中是对应的):

I. list只能使用查询缓存(但查询缓存在交易系统中作用不大),不能使用二级缓存中的单个实体。但是列表找到的对象会被写入二级缓存,但它一般只生成几条SQL语句,很多情况下只是一条(不相关)。

二。迭代器可以使用二级缓存。对于一个查询语句,它会先从数据库中找出所有符合条件的记录的ID,然后通过ID进行缓存。对于不在缓存中的记录,它会构造一个语句从数据库中找出。所以很容易知道,如果缓存中没有符合条件的记录,使用迭代器会产生N+1条SQL语句(N是符合条件的记录数)。

三。借助迭代器和缓存管理API,可以很好地解决海量数据查询中的内存问题,比如:

while(it.hasNext()){

YouObject object =(YouObject)it . next();

session . evict(you object);

session factory . evice(you object . class,you object . getid());

}

如果使用list方法,您可能会得到一个OutofMemory错误。

从上面的解释,我想你应该知道如何使用这两种方法。

7.器械包的选择

在“19.5”中有详细解释。了解HIBERNATE 3.1文档的“收集性能”。

8.交易控制

事务方面对性能有影响,包括事务模式的选择、事务隔离级别和锁的选择。

a)交易模式的选择:如果不涉及多个交易经理,则不需要JTA,只需要JDBC交易控制就够了。

b)事务隔离级别:参考标准SQL事务隔离级别。

c)锁的选择:悲观锁(一般由特定的事务管理器实现)效率较低,但对于长事务是安全的。乐观锁定(通常在应用程序级实现),比如版本字段可以在HIBERNATE中定义。显然,如果有多个应用程序操作数据,而这些应用程序不使用相同的乐观锁定机制,乐观锁定将会失败。所以不同的数据应该有不同的策略。和以前的许多案例一样,我们经常在效率和安全/准确性之间找到平衡。无论如何,优化不是一个纯粹的技术问题,你应该对你的应用和业务特性有足够的了解。

9、批量操作

即使使用JDBC,在更新大量数据时,批处理和不批处理的效率也有很大差别。我们可以通过设置batch_size来支持批处理操作。

比如你想批量删除一个表中的对象,比如“删除账号”,你会发现HIBERNATE找出所有账号的ID,然后删除。这主要是维护二级缓存,所以效率肯定不高。后续版本中增加了批量删除/更新,但这并不能解决缓存维护的问题。也就是说,由于二级缓存的维护问题,HIBERNATE的批量操作效率并不尽如人意!