一、springboot整合redis,基于springboot的缓存技术
先在这里说明所用的版本号为2.1.7,一定得注意版本的问题,因为springboot1.0与springboot‘2.0整合redis上有很多不同,这里所用的是2.0以上的版本,至于springboot2.0与springboot1.0的redis配置,参照springboot1.5.x版本于springboot2.x版本reids使用的不同
还有,此篇博客是基于上一篇博客的续集,不明此参照上一篇博客springboot的缓存机制
1、首先,引入相关的依赖
<!--加入对redis的依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<!--2.0以上默认的连接池为lettuce,在这里采用jedis,所以需要排除lettuce的依赖-->
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--加入redis的jar包,并引用依赖包conmons-pool-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<!--spring2.0集成redis所需common-pool2-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.5.0</version>
<!--<version>2.4.2</version>-->
</dependency>
2.x默认的连接池为lettuce,1.5.x默认的连接池为jedis,这里我们排除对lettuce的依赖,加入jedis连接池的jar以及2.x中redis所需的common-pool2的jar
注:一定要重新引入jedis连接池的jar以及commons-pool2的依赖,博主之前没有引入(看的1.x的教程,自己却用2.x的版本)导致自己配置redis的缓存时,出现了方法链接池对象无法注入的情况,所以要特别提醒,一定要看好版本,对应好相关的配置!!!!!,错误截图:
即RedisCoonectionFactory对象无法注入。
2、改掉springboot默认的CacheManager
springboot的注解@EnableCaching默认开启的为SimpleCacheConfiguration缓存,springboot会根据以下去侦测缓存的提供者:
默认配置的缓存管理器只能有一种实现,若同时配置多个缓存管理器,排序靠前的会优先加载,之后不会生效,也可以通过@Primary注解让其优先级变高。
因此,我们要用redis的缓存管理器,需要自己配置缓存管理器。
3、配置redis的缓存管理器
在application.properties中配置redis连接参数:
#Matser的ip地址
spring.redis.host=47.94.9.215
#端口号
spring.redis.port=6379
#如果有密码
spring.redis.password=
#客户端超时时间单位是毫秒 默认是2000
spring.redis.timeout=10000
#最大空闲数
spring.redis.maxIdle=300
#连接池的最大数据库连接数。设为0表示无限制,如果是jedis 2.4以后用redis.maxTotal
#redis.maxActive=600
#控制一个pool可分配多少个jedis实例,用来替换上面的redis.maxActive,如果是jedis 2.4以后用该属性
spring.redis.maxTotal=1000
#最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制。
spring.redis.maxWaitMillis=1000
#连接的最小空闲时间 默认1800000毫秒(30分钟)
spring.redis.minEvictableIdleTimeMillis=300000
#每次释放连接的最大数目,默认3
spring.redis.numTestsPerEvictionRun=1024
#逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1
spring.redis.timeBetweenEvictionRunsMillis=30000
#是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个
spring.redis.testOnBorrow=true
#在空闲时检查有效性, 默认false
spring.redis.testWhileIdle=true
注意:这里的配置也跟1.x版本的不同,需要特别注意!!!
4、完成配置
通过以上的配置,springboot默认的缓存机制将变为redis缓存,使用@Cacheable将会向redis中缓存数据。
原因:引入redis的以来之后会自动配置redis缓存,同时帮我配置了两个对象,RedisTemplate以及StringRedisTemplate,用来操作redis缓存。
二、使用对象向redis中存入数据。
1、使用StringRedisTemplate类来向redis中存储string-string数据。
@Autowired
private StringRedisTemplate stringRedisTemplate; //注入对象
@Override
public void insert(User user) {
userMapper.insert(user);
}
@Override
public User findUserByID(Integer id) {
System.out.println("查询了数据库");
ValueOperations<String, String> stringStringValueOperations = stringRedisTemplate.opsForValue(); //存入
stringStringValueOperations.set("xuyong","uahdu"); //取的话这里调用get方法,传入key
return (User) userMapper.findUserByID(id);
}
执行完之后,可以看到redis的缓存中增加了
提示:这里使用类来操作redis,此时不用使用@EnableCaching来开启注解,直接使用缓存即可。
当然,也可以hash来存储数据,此时为:
HashOperations<String, Object, Object> stringObjectObjectHashOperations = stringRedisTemplate.opsForHash();
stringObjectObjectHashOperations.put("duau","daj","dand");
- 2、StringRedisTemplate的方法对应操作list、set有:
这里给出封装了StringRedisTemplate的工具类,只对应操作string-string类型
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
/**
* 工具类
*
*/
@Service
@Slf4j
public class IRedisService {
@Autowired
protected StringRedisTemplate redisTemplate;
/**
* 写入redis缓存(不设置expire存活时间)
* @param key
* @param value
* @return
*/
public boolean set(final String key, String value){
boolean result = false;
try {
ValueOperations operations = redisTemplate.opsForValue();
operations.set(key, value);
result = true;
} catch (Exception e) {
log.error("写入redis缓存失败!错误信息为:" + e.getMessage());
}
return result;
}
/**
* 写入redis缓存(设置expire存活时间)
* @param key
* @param value
* @param expire
* @return
*/
public boolean set(final String key, String value, Long expire){
boolean result = false;
try {
ValueOperations operations = redisTemplate.opsForValue();
operations.set(key, value);
redisTemplate.expire(key, expire, TimeUnit.SECONDS);
result = true;
} catch (Exception e) {
log.error("写入redis缓存(设置expire存活时间)失败!错误信息为:" + e.getMessage());
}
return result;
}
/**
* 读取redis缓存
* @param key
* @return
*/
public Object get(final String key){
Object result = null;
try {
ValueOperations operations = redisTemplate.opsForValue();
result = operations.get(key);
} catch (Exception e) {
log.error("读取redis缓存失败!错误信息为:" + e.getMessage());
}
return result;
}
/**
* 判断redis缓存中是否有对应的key
* @param key
* @return
*/
public boolean exists(final String key){
boolean result = false;
try {
result = redisTemplate.hasKey(key);
} catch (Exception e) {
log.error("判断redis缓存中是否有对应的key失败!错误信息为:" + e.getMessage());
}
return result;
}
/**
* redis根据key删除对应的value
* @param key
* @return
*/
public boolean remove(final String key){
boolean result = false;
try {
if(exists(key)){
redisTemplate.delete(key);
}
result = true;
} catch (Exception e) {
log.error("redis根据key删除对应的value失败!错误信息为:" + e.getMessage());
}
return result;
}
/**
* redis根据keys批量删除对应的value
* @param keys
* @return
*/
public void remove(final String... keys){
for(String key : keys){
remove(key);
}
}
}
2、使用RedisTemplate来存取对象
根据源码可以看出,RedisTemplate只能存取object-object类型的数据,因此对其进行重写,由源码可以知道,原来的RedisTemplate只有在容器中不存在redisTemplate的bean时才会注入bean,否则将不会注入。
自己定义个配置类,继承CachingConfigurerSupport,重新定义redisTemplate,使其存入的对象自动转为json格式。
@Configuration
public class RedisConfiguration extends CachingConfigurerSupport {
/**
*
* 注入redisTemplate,这里是将原来的<Object,Object>改变为<String,Object>
*
* @param
* @return
*/
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory jedisConnectionFactory) {
//用json格式存储
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); //将这个注释掉将不会缓存对象的类型
jackson2JsonRedisSerializer.setObjectMapper(om);
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(jedisConnectionFactory);
template.setKeySerializer(jackson2JsonRedisSerializer);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setHashKeySerializer(jackson2JsonRedisSerializer);
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
此时,对RedisTemplate对象进行操作,向redis添加缓存。
@Autowired
private RedisTemplate redisTemplate;
@Override
public void insert(User user) {
userMapper.insert(user);
}
@Override
public User findUserByID(Integer id) {
System.out.println("查询了数据库");
/* ValueOperations<String, String> stringStringValueOperations = stringRedisTemplate.opsForValue();
stringStringValueOperations.set("xuyong","uahdu");
HashOperations<String, Object, Object> stringObjectObjectHashOperations = stringRedisTemplate.opsForHash();
stringObjectObjectHashOperations.put("duau","daj","dand");*/
ValueOperations valueOperations = redisTemplate.opsForValue();
valueOperations.set("du",userMapper.findUserByID(id)); //取数时使用get,取出来也为json格式:User{id=2, username='jj', password='619861'}
return (User) userMapper.findUserByID(id);
}
运行后redis中增加缓存:
将配置类中的 om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);注释掉将不会缓存类型,如下:
使用哪一种可以自己选择!!!
对应的其它list、set、hash操作的redisTemplate的方法有如下:
三、总结
采用redis缓存有两种方法,一种直接使用springboot的缓存机制,使用注解来向redis中缓存数据,另一种直接使用RedisTemplate和StringRedisTemplate这两个类来向redis中缓存数据。不管使用哪种,都要特别注意版本问题,再次提示,1.x和2.x的springboot对于redis缓存配置是不一样的。