启用hibernate 缓存application.yml配置:
spring:
jpa:
properties:
javax:
persistence:
sharedCache:
mode: ENABLE_SELECTIVE
hibernate:
cache:
use_query_cache: true
use_second_level_cache: true
region:
factory_class: org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory
sharedCacheModel:
ENABLE_SELECTIVE,默认值,除非被@Cacheable显式声明要缓存,否则默认不缓存
DISABLE_SELECTIVE,除非被@Cacheable显式声明不缓存,否则默认缓存
ALL,总是被缓存
NONE,总是不缓存
hibernate实现中只有三种缓存类型:
一级缓存:默认启用,无法关闭,session级别, 同一个session内部,一级缓存生效,同一个id的对象只有一个。不同session,一级缓存无效
二级缓存: sessionFactory级别,使用方式有两种:第一种不使用hibernate的@cache标记,直接在实体上用@cacheable(javax.persistence.Cacheable)标记并且要配置缓存配置项: javax.persistence.sharedCache.mode:ENABLE_SELECTIVE, 第二种用hibernate的@cache标记使用,
1、二级缓存针对列表数据默认只缓存id,再通过id从数据库中查找
2、二级缓存缓存的仅仅是对象,如果查询出来的是对象的一些属性,则不会被加到缓存中去
3、 只有当 HQL 查询语句完全相同时,连参数设置都要相同,此时查询缓存才有效
查询缓存: 使用方式 queryImpl.setCacheable(true);必须设置才会生效
查询缓存缓存的也仅仅是对象的id,所以第一条 sql 也是将对象的id都查询出来,但是当我们后面如果要得到每个对象的信息的时候,此时又会发sql语句去查询,所以,如果要使用查询缓存,我们一定也要开启我们的二级缓存,这样就不会出现 N+1 问题了
private void setHibernateQuery(Query query) {
if (query instanceof QueryImpl) {
QueryImpl<?> queryImpl = (QueryImpl<?>) query;
queryImpl.setCacheable(true);
}
}
ehcache.xml配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<ehcache name="HIBERNATE_CACHE" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://www.ehcache.org/ehcache.xsd"
updateCheck="true" monitoring="autodetect" dynamicConfig="true">
<!-- 指定二级缓存存放在磁盘上的位置,可以使用磁盘目录,也可以使用Java System Property目录,user.home是用户目录、user.dir是用户当前工作目录、java.io.tmpdir是默认临时文件路径 -->
<diskStore path="target/cache/hibernate" />
<transactionManagerLookup
class="net.sf.ehcache.transaction.manager.DefaultTransactionManagerLookup"
properties="jndiName=java:/TransactionManager" propertySeparator=";" />
<defaultCache maxEntriesLocalHeap="0" eternal="false" diskPersistent="false"
timeToIdleSeconds="3600" timeToLiveSeconds="0">
<!--<terracotta/> -->
</defaultCache>
<!--可以给每个实体类指定一个配置文件,通过name属性指定,要使用类的全名
1. name:Cache的唯一标识。
2. maxElementsInMemory:内存中最大缓存对象数。
3. eternal:Element是否永久有效,一旦设置true,timeout将不起作用。
4. timeToIdleSeconds:设置Element在失效前的允许闲置时间。仅当element不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
5. timeToLiveSeconds:设置Element在失效前允许存活时间。最大时间介于创建时间和失效时间之间。仅当element不是永久有效时使用,默认是0.,也就是element存活时间无穷大。
6. overflowToDisk:配置此属性,当内存中Element数量达到maxElementsInMemory时,Ehcache将会Element写到磁盘中。
7. maxElementsOnDisk:磁盘中最大缓存对象数,若是0表示无穷大。
8. memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理缓存中的内容。默认策略是LRU(最近最少使用),你也可以设置为FIFO(先进先出)或是LFU(较少使用)
9. diskSpoolBufferSizeMB : 这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区
10. maxEntriesLocalHeap堆内存中最大缓存对象数,0没有限制(必须设置)
11. maxEntriesLocalDisk硬盘最大缓存个数 -->
<cache name="org.hibernate.cache.internal.StandardQueryCache"
maxEntriesLocalHeap="0" eternal="false" timeToIdleSeconds="1200">
<persistence strategy="localTempSwap" />
</cache>
<cache name="org.hibernate.cache.spi.UpdateTimestampsCache"
maxEntriesLocalHeap="5000" eternal="true">
<persistence strategy="localTempSwap" />
</cache>
</ehcache>
org.springframework.cache.annotation.Cacheable注解使用异常问题:
java.lang.IllegalArgumentException: Cannot find cache named '缓存名' for Builder[加了cacheable注解的方法名] caches=[缓存名] | key='#groupName' | keyGenerator='' | cacheManager='' | cacheResolver='' | condition='' | unless='' | sync='false'
@Cacheable(value = "findByGroup", key = "#groupName")
如果findByGroup未在ehcache.xml中配置,会出现无法找到缓存名的异常,可以使用CaffeineCacheManager或其他的缓存组件作为应用层缓存替换掉EhCacheCacheManager,就可以不用配置缓存名了,数据库缓存还是使用的ehcache,不会产生影响
@EnableCaching
@Configuration
public class BcCacheManagerConfig {
@Bean
@ConditionalOnMissingBean(CacheManager.class)
public CaffeineCacheManager caffeineCacheManager() {
return new CaffeineCacheManager();
}
}
相关包引入
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
</parent>
----------------------------------------------------------------------------
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.ben-manes.caffeine/caffeine -->
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
<!-- 集成ehcache需要的依赖 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<exclusions>
<exclusion>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
</exclusion>
</exclusions>
</dependency>