由于最近新上的项目很多模块没有做数据缓存,大量的请求都会到数据库去查询,为了减轻数据库的压力以及提高网站响应速度,所以在这里采用了spring 提供的注解+redis实现对数据的缓存,主要针对非热点数据,例如 省市,银行卡列表等做缓存,在这里主要是查询做一个缓存实例。
- pom.xml (加入spring和reids jar包)
<!-- redis --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-redis</artifactId> </dependency>
- spring-redis.xml配置(通过配置线程池方式连接redis, 提供操作redis的api)
<!-- jedis 配置 --> <!-- redis连接池的配置 --> <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxTotal" value="100" /> <property name="maxIdle" value="${redis.maxIdle}"/> <property name="minIdle" value="${redis.minIdle}"/> <property name="maxWaitMillis" value="${redis.maxWaitMillis}"/> <property name="testOnBorrow" value="${redis.testOnBorrow}"/> <property name="testOnReturn" value="${redis.testOnReturn}"/> </bean> <!-- redis的连接池pool,不是必选项:timeout/password --> <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" > <property name="usePool" value="true"></property> <property name="hostName" value="${redis.host}" /> <property name="port" value="${redis.port}" /> <property name="password" value="${redis.password}" /> <property name="timeout" value="100000" /> <property name="database" value="0"></property> <constructor-arg index="0" ref="jedisPoolConfig" /> </bean>
<!-- 配置redis模板,需要注入到 RedisCacheManager by dada --> <bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate"> <property name="connectionFactory" ref="connectionFactory" /> <property name="keySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" /> </property> <property name="valueSerializer"> <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" /> </property> </bean> <!-- 配置缓存 by dada --> <bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager"> <constructor-arg ref="redisTemplate" /> <!--<property name="defaultExpiration" value="300"></property>--> <property name="usePrefix" value="true"></property> <property name="expires"> <util:map>
<!-- 指定key的时间为1500秒 --> <entry key="get_bank_province_list" value="1500"></entry> <entry key="get_areas_bypid_list" value="1500"></entry> </util:map> </property> </bean>
- 由于使用的是spring提供的注解方式实现redis缓存,所以需要在spring配置文件加上cache标签,否则注解不会生效。
<!-- 启用缓存注解功能,这个是必须的,否则注解不会生效,另外,该注解一定要声明在spring主配置文件中才会生效,这个cacheManager 必须指向redis配置里面的 RedisCacheManager--> <cache:annotation-driven cache-manager="cacheManager" />
配置好后如何使用:
- 在需要用到缓存的Service实现类方法加上对应的注解,例如一般查询方法就是加上@Cacheable; 注意下面getBankProvince这个方法中我并没有传入参数,如果不带参数查询则要定义一个key(如何自定义key参见第2条),否则运行时候会出现无法找到key的错误,至于为什么报错下次会详细分析。
- 我在注解里定义了一个key #root.methodName,代表的是默认使用方法名称 getBankProvince 作为key的后缀, 则拼接后的完整key为 get_bank_province_list:getBankProvince。
- 第一次请求 getBankProvince方法 Spring会做一个切面操作,也就是先请求redis,如果redis发现没有这个key,则会查询数据库,查询完成后会将数据存到redis。
- 第二次请求后由于第一次请求已经把数据存到了redis, 所以能从redis查询到数据,则不会再去重复查询数据库了。
/**
* @Cacheable
* 应用到读取数据的方法上,先从缓存中读取,如果没有再从DB获取数据,然后把数据添加到缓存中
* unless 表示条件表达式成立的话不放入缓存
*/
@Cacheable(value = "get_bank_province_list",key = "#root.methodName")
public List<SAreasEntity> getBankProvince() {
List<SAreasEntity> list = new ArrayList<SAreasEntity>();
List<SAreasItem> listItem = sAreasMapper.getBankProvince();
for(int i=0;i<listItem.size();i++){
SAreasEntity sareasEntity=new SAreasEntity();
SAreasItem sareasItem=listItem.get(i);
sareasEntity.setId(sareasItem.getId());
sareasEntity.setName(sareasItem.getName());
sareasEntity.setPid(sareasItem.getPid());
sareasEntity.setCity_name(sareasItem.getCity_name());
list.add(sareasEntity);
}
return list;
}
说明
@Cacheable
应用到读取数据的方法上,即可缓存的方法,如查找方法:先从缓存中读取,如果没有再调用方法获取数据,然后把数据添加到缓存中。
除了上述使用方法参数作为key之外,Spring还为我们提供了一个root对象可以用来生成key。通过该root对象我们可以获取到以下信息。
属性名称 |
描述 |
示例 |
methodName |
当前方法名 |
#root.methodName |
method |
当前方法 |
#root.method.name |
target |
当前被调用的对象 |
#root.target |
targetClass |
当前被调用的对象的class |
#root.targetClass |
args |
当前方法参数组成的数组 |
#root.args[0] |
caches |
当前被调用的方法使用的Cache |
#root.caches[0].name |