Hibernate是一个很好的ORM,对于性能优化也提供了很多方案。其中缓存方案中有一级缓存(默认开启),二级缓存(默认关闭)。在我参与项目中开启了二级缓存,这是一个老项目,可是感觉没有很好的效果,于是就学习了hibernate的二级缓存,尝试解决问题。对于二级缓存的选择应当是根据自己的需求选择是否开启,开启到何种程度。
项目相关信息:
hibernate版本:4.3.8.Final
数据库:mysql 5.7.18
主要的缓存
- EHCache:快速、轻量级、易用的线程内缓存。支持只读、读写缓存。支持内存,磁盘缓存。但不支持集群。
- OSCache:一个大型解决方案的一部分,提供对jsp页面和任何对象的缓存,强大而又灵活。也支持只读,读写缓存,支持内存、磁盘缓存。同时提供基于JavaGroups or JMS的基础集群支持。
- SwarmCache:提供基于JavaGroups的简单集群支持。支持只读、非严格读写。适合读远远多于写的应用。
- JBoss TreeCache:提供了强大的同步以及事务缓存。如果需要一个具有事务能力的高速缓存架构,这将是一个很好的选择。当然,也支持集群。
缓存策略
- Read-only: 这种策略适合一直读但不更新的情况,性能是最好的。
- Read/write: 这种策略适合需要修改数据的情况,不过需要更多的性能消耗。
- Nonstrict read/write: 这种策略不保证两个事务不会同时修改相同数据。适合大多时候读,极少需要修改。
- Transactional: 仅能在JTA环境中使用的完全事务
重要的配置
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>
<prop key="hibernate.cache.provider_configuration_file_resource_path">ehcache.xml</prop>
</props>
</property>
hibernate.cache.use_second_level_cache:开启二级缓存
hibernate.cache.use_query_cache:开启查询缓存
hibernate.cache.region.factory_class:缓存区实现类
hibernate.cache.provider_configuration_file_resource_path:缓存配置文件
defaultCache
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
maxElementsOnDisk="1000000"
overflowToDisk="true"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
maxElementsInMemory:内存中最大保存实体数
Eternal:是否永久保存
timeToIdleSeconds:缓存对象在多少秒内没有被使用就清除
timeToLiveSeconds:缓存对象在过期前可以缓存多少秒
maxElementsOnDisk:磁盘中最大保存实体数
overflowToDisk:系统宕机时是否保存到磁盘上
memoryStoreEvictionPolicy:清除对象的方式
二级缓存的开启
①开启二级缓存。
二级缓存默认是关闭的,开启需要在配置文件中手动添加:
<prop key="hibernate.cache.use_second_level_cache">true</prop>
除此,还需要对需要缓存的实体添加cache注解,注解如下:
@Entity
@Table(name = "user", schema = "", catalog = "")
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public class UserEntity {
......
}
至此,当使用list、get、load等时,获取的数据会添加到二级缓存中。
但是,只有使用load、get时才会使用二级缓存中的数据。因为这个时候二级缓存中仅仅使用entity的标识属性作为key来缓存实体。
List、条件查询都会直接从数据库中获取数据。(未开启条件查询时)
②开启查询缓存
查询缓存默认关闭,打开方式如下:
<prop key="hibernate.cache.use_query_cache">true</prop>
对于需要缓存查询语句需要添加”setCacheable(true)”
<prop key="hibernate.cache.use_query_cache">true</prop>
将会以本条sql语句作为key,如果查询语句中有参数,将会由参数组装成sql语句作为key:
select
this_.id as id1_2_0_,
this_.name as name2_2_0_,
this_.version as version3_2_0_
from
test.user this_
where
this_.id='0b0ee7bb-8fba-4f87-91c4-db69f249fcc4'
当下一次查询语句组装的 sql语句于缓存的 key一致时(相同的语句,相同的参数),才会使用二级缓存中的数据。
缓存中数据的添加更新删除
1,添加
对于对象的添加,list、get、load、hql、sql获得的数据,都会以对象的标识属性为key进行缓存。
如果开启查询缓存,list、hql、sql会进行两项缓存:①以对象的标识属性为key进行缓存;②以查询语句与参数组成的sql语句为key进行查询结果缓存。
2,删除与更新
①Read-only
不能更新删除从缓存中获取的对象。
通过hql、sql等直接修改删除的,会清除该实体类的所有entity,以及相关查询缓存。
②其他
Update、delete数据时,如果数据是从缓存中读取的或依据对象标识属性从数据库读取的(即要修改的属性是以标识属性从缓存或数据库中获取),再做修改,仅清除该实体,以及相关的查询缓存。
如果通过hql、sql来update、delete,则清除实体类的所有entity,以及相关的查询缓存。
参考:
http://www.devx.com/dbzone/Article/29685?pf=true
http://www.iteye.com/topic/18904