Redis 作为一个nosql 数据库,在项目中的作用是非常重要的。本章将介绍 springboot1.5 集成 Redis的基础知识。
个人学习总结:
链接:【springboot、springcloud、docker 等,学习目录】
学习链接: Redis中文网:http://www.redis.cn
Redis的下载,安装,以及客户端在这里都可以找到对应入口。可自行下载安装,我使用的是阿里云docker 镜像安装,Docker 系列会涉及。
1、String(字符串): 一个key对应一个value, 可以包含任何数据。比如jpg图片或者序列化的对象。最大能储存512MB。
2、Hash(哈希): 键值对集合,类似对象,
redis> HMSET person field1 "Hello" field2 "World"
redis> HGET person field1"Hello"
redis> HGET person field2"World"
3、List(列表): 简单的字符串列表,按照插入的顺序排序,可以添加一个字符串到头部或者尾部。
redis 127.0.0.1:6379> lpush runoob redis(integer) 1
redis 127.0.0.1:6379> lpush runoob mongodb(integer) 2
redis 127.0.0.1:6379> lpush runoob rabitmq(integer) 3
redis 127.0.0.1:6379> lrange runoob 0 10
1) "rabitmq"
2) "mongodb"
3) "redis"
redis 127.0.0.1:6379>
4、Set(集合): String类型的无序集合。注意集合中的元素是无序但唯一的。重复元素插入将被忽略。
5、Zset(Socted set 有序集合): String 类型元素的集合,但元素可以重复。
redis 127.0.0.1:6379> zadd runoob 0 redis(integer) 1
redis 127.0.0.1:6379> zadd runoob 0 mongodb(integer) 1
redis 127.0.0.1:6379> zadd runoob 0 rabitmq(integer) 1
redis 127.0.0.1:6379> zadd runoob 0 rabitmq(integer) 0
redis 127.0.0.1:6379> > ZRANGEBYSCORE runoob 0 1000
1) "mongodb"
2) "rabitmq"
3) "redis"
1、pom依赖:(使用的是1.5.1版本的springboot,所以依赖选择带有data的)
org.springframework.boot
spring-boot-starter-data-redis
2、application.properties文件中添加
## Redis 配置
## Redis数据库索引(默认为0)
spring.redis.database=0
## Redis服务器地址
spring.redis.host=127.0.0.1
## Redis服务器连接端口
spring.redis.port=6379
## Redis服务器连接密码(默认为空)
spring.redis.password=
## 连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=8
## 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1
## 连接池中的最大空闲连接
spring.redis.pool.max-idle=8
## 连接池中的最小空闲连接
spring.redis.pool.min-idle=0
## 连接超时时间(毫秒)
spring.redis.timeout=3000
因为springboot引入了redis的starter,完成以上配置redis可以正常使用了。个性化的东西可以添加到 redis的配置类中,请看下文Redis自定义配置。
1、源码:我们搜索 RedisAutoConfiguration 类:
@Configuration
@ConditionalOnClass({JedisConnection.class, RedisOperations.class, Jedis.class})
@EnableConfigurationProperties({RedisProperties.class})
public class RedisAutoConfiguration {
...
@Configuration
protected static class RedisConfiguration {
protected RedisConfiguration() {
}
@Bean
@ConditionalOnMissingBean(
name = {"redisTemplate"}
)
public RedisTemplate
发现:这里引入了Jedis 的操作、注入了redisTemplate和stringRedisTemplate。使用的时候只需要自动注入即可。
2、测试:使用@Test 测试
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootApplicationTests {
/**
* RedisAutoConfiguration 中注入 :
* redisTemplate : k - v 操作对象的
* stringRedisTemplate : k - v 操作字符串的
*/
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private StringRedisTemplate stringRedisTemplate;
/**
* 操作String 使用 stringRedisTemplate
* stringRedisTemplate.opsForValue() 操作String
* stringRedisTemplate.opsForList() 操作list 列表
* stringRedisTemplate.opsForSet() 操作set集合
* stringRedisTemplate.opsForHash() 操作hash散列
* stringRedisTemplate.opsForZSet() 操作有序集合
*
* 后面直接跟上 redis的命令即可。
*/
@Test
public void test01(){
// 操作String
// stringRedisTemplate.opsForValue().append("str1","hello");
// String str1 = stringRedisTemplate.opsForValue().get("str1");
// // >>>>>>>>>>>>>>>>>>str: hellohello 原因: 执行了两次 追加。
// log.info(">>>>>>>>>>>>>>>>>>str: {}",str1);
// 操作list 列表
stringRedisTemplate.opsForList().leftPush("list1","广东省");
stringRedisTemplate.opsForList().leftPush("list1","22222");
}
/**
* 测试保存对象 使用 redisTemplate
*/
@Test
public void test02(){
User user = new User();
user.setId(1);
user.setName("ron");
redisTemplate.opsForValue().set("person",user);
}
}
注意:此处的实体类(User)需实现序列化接口Serializable
3、redis客户端中出现(类似 \xac\xed\x00\x05t\x00)乱码。
乱码分析: 查看 RedisTemplate 类源码
public class RedisTemplate extends RedisAccessor implements RedisOperations, BeanClassLoaderAware {
...
// 序列化器
private RedisSerializer keySerializer = null;
private RedisSerializer valueSerializer = null;
private RedisSerializer hashKeySerializer = null;
private RedisSerializer hashValueSerializer = null;
...
public void afterPropertiesSet() {
super.afterPropertiesSet();
boolean defaultUsed = false;
if(this.defaultSerializer == null) {
this.defaultSerializer = new JdkSerializationRedisSerializer(this.classLoader != null?this.classLoader:this.getClass().getClassLoader());
}...
}
}
可以看到 redisTemplate 保存对象默认使用 JDK 序列化机制,序列化后的数据保存到Redis中乱码。
乱码解决:
方案1、将对象转为json
方案2、改变RedisTemplate默认序列化规则。
/**
* @Auther: xf
* @Date: 2018/11/21 22:07
* @Description: 自定义序列化器
*/
@Configuration
public class MyRedisConfig {
@Autowired
private RedisTemplate redisTemplate;
@Bean
public RedisTemplate redisTemplateInit() {
//设置序列化Key的实例化对象
redisTemplate.setKeySerializer(new StringRedisSerializer());
//设置序列化Value的实例化对象
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
return redisTemplate;
}
}
再次测试,乱码解决。
Redis配置类:并非必需,根据自身开发环境要求选取配置
/**
* @Auther: admin
* @Date: 2018/11/20 23:10
* @Description: redis 配置类
*/
@Slf4j
@Configuration
@EnableCaching//(缓存支持)
//继承CachingConfigurerSupport,重写CacheManager方法。
public class RedisConfig extends CachingConfigurerSupport {
/**
* 注入 RedisConnectionFactory
*/
@Autowired
RedisConnectionFactory redisConnectionFactory;
/**
* 指定key的生成策略
* @return KeyGenerator
*/
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
String[] value = new String[1];
// sb.append(target.getClass().getName());
// sb.append(":" + method.getName());
Cacheable cacheable = method.getAnnotation(Cacheable.class);
if (cacheable != null) {
value = cacheable.value();
}
CachePut cachePut = method.getAnnotation(CachePut.class);
if (cachePut != null) {
value = cachePut.value();
}
CacheEvict cacheEvict = method.getAnnotation(CacheEvict.class);
if (cacheEvict != null) {
value = cacheEvict.value();
}
sb.append(value[0]);
//获取参数值
for (Object obj : params) {
sb.append(":" + obj.toString());
}
return sb.toString();
}
};
}
/**
* 实例化 CacheManager 对象,指定使用RedisCacheManager作缓存管理
*
* @return CacheManager
*/
@Bean
public CacheManager cacheManager(RedisTemplate redisTemplate) {
RedisCacheManager rcm = new RedisCacheManager(redisTemplate);
// 设置缓存过期时间(单位:秒),60秒
rcm.setDefaultExpiration(600);
return rcm;
}
/**
* 实例化 RedisTemplate 对象
* @return RedisTemplate
*/
@Bean
public RedisTemplate functionDomainRedisTemplate() {
RedisTemplate redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
initDomainRedisTemplate(redisTemplate);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
/**
* 设置数据存入 redis 的序列化方式
* redisTemplate 序列化默认使用的jdkSerializeable, 存储二进制字节码, 所以自定义序列化类
*
* @param redisTemplate
*/
private void initDomainRedisTemplate(
RedisTemplate redisTemplate) {
//key序列化方式;(不然会出现乱码;),但是如果方法上有Long等非String类型的话,会报类型转换错误;
//所以在没有自己定义key生成策略的时候,以下这个代码建议不要这么写,可以不配置或者自己实现ObjectRedisSerializer
//或者JdkSerializationRedisSerializer序列化方式;
// 使用Jackson2JsonRedisSerialize 替换默认序列化
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(
Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
//// string结构的数据,设置value的序列化规则和 key的序列化规则
//StringRedisSerializer解决key中午乱码问题。//Long类型不可以会出现异常信息;
redisTemplate.setKeySerializer(new StringRedisSerializer());
//value乱码问题:Jackson2JsonRedisSerializer
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
//设置Hash结构的key和value的序列化方式
//redisTemplate.setHashKeySerializer(jackson2JsonRedisSerializer);
//redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
}
/**
* redis数据操作异常处理
* 这里的处理:在日志中打印出错误信息,但是放行
* 保证redis服务器出现连接等问题的时候不影响程序的正常运行,使得能够出问题时不用缓存
* @return
*/
@Bean
@Override public CacheErrorHandler errorHandler() {
CacheErrorHandler cacheErrorHandler = new CacheErrorHandler() {
@Override public void handleCacheGetError(RuntimeException e,
Cache cache, Object key) {
log.error("redis异常:key=[{}]", key, e);
}
@Override public void handleCachePutError(RuntimeException e,
Cache cache, Object key, Object value) {
log.error("redis异常:key=[{}]", key, e);
}
@Override public void handleCacheEvictError(RuntimeException e,
Cache cache, Object key) {
log.error("redis异常:key=[{}]", key, e);
}
@Override public void handleCacheClearError(RuntimeException e,
Cache cache) {
log.error("redis异常:", e);
}
};
return cacheErrorHandler;
}
/**
* 实例化 ValueOperations 对象,可以使用 String 操作
* @param redisTemplate
* @return
*/
@Bean
public ValueOperations valueOperations(
RedisTemplate redisTemplate) {
return redisTemplate.opsForValue();
}
/**
* 实例化 HashOperations 对象,可以使用 Hash 类型操作
* @param redisTemplate
* @return
*/
@Bean
public HashOperations hashOperations(
RedisTemplate redisTemplate) {
return redisTemplate.opsForHash();
}
/**
* 实例化 ListOperations 对象,可以使用 List 操作
* @param redisTemplate
* @return
*/
@Bean
public ListOperations listOperations(
RedisTemplate redisTemplate) {
return redisTemplate.opsForList();
}
/**
* 实例化 SetOperations 对象,可以使用 Set 操作
* @param redisTemplate
* @return
*/
@Bean
public SetOperations setOperations(
RedisTemplate redisTemplate) {
return redisTemplate.opsForSet();
}
/**
* 实例化 ZSetOperations 对象,可以使用 ZSet 操作
* @param redisTemplate
* @return
*/
@Bean
public ZSetOperations zSetOperations(
RedisTemplate redisTemplate) {
return redisTemplate.opsForZSet();
}