【Redis】 springboot集成Redis

1、pom文件中引入依赖

redis的依赖配置:

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis</artifactId>
		</dependency>
2、配置文件中的配置
spring:
  redis:
    # Redis的服务器地址
    host: localhost
    # Redis的连接端口
    port: 6379
    # Redis服务器连接密码(默认为空)
    password: 
    # 连接超时时间(毫秒)
    timeout: 1000
    # Redis数据库索引(默认为0);Redis数据库默认有16个独立的数据库,编号0-15
    database: 0
3、为什么要自定义redisTemplate

    一般情况下,配置完以上的内容就可以直接使用RedisTemplate了,但是当数据存储到Redis的时候,键(key)和值(value)都是通过Spring提供的Serializer序列化到数据库的。

RedisTemplate默认使用的是JdkSerializationRedisSerializer;
StringRedisTemplate默认使用的是StringRedisSerializer。

Spring Data JPA为我们提供了下面的Serializer:

  • GenericToStringSerializer
  • Jackson2JsonRedisSerializer
  • JacksonJsonRedisSerializer
  • JdkSerializationRedisSerializer
  • OxmSerializer
  • StringRedisSerializer。

序列化方式对比:

  • JdkSerializationRedisSerializer: 使用JDK提供的序列化功能。 优点是反序列化时不需要提供类型信息(class),但缺点是实体类需要实现Serializable接口,如果操作的实体类没有实现Serializable接口就会报IllegalArgumentException错误;还有序列化后的结果非常庞大,是JSON格式的5倍左右,这样就会消耗redis服务器的大量内存;

  • Jackson2JsonRedisSerializer: 使用Jackson库将对象序列化为JSON字符串。优点是速度快,序列化后的字符串短小精悍,不需要实现Serializable接口。但缺点也非常致命,那就是此类的构造函数中有一个类型参数,必须提供要序列化对象的类型信息(.class对象)。 通过查看源代码,发现其只在反序列化过程中用到了类型信息。

注意: 在使用redisTemplate时,如果使用Jackson2JsonRedisSerializer、JdkSerializationRedisSerializer对值进行序列化的话,然后对值进行自增计算的时候会报错:ERR value is not an integer or out of range。
原因分析: Jackson2JsonRedisSerializer是先将对象转化为json字符串然后进行存储;JdkSerializationRedisSerializer对象序列化后的值有类信息、版本号等,所以是一个包含很多字母的字符串,所以根本无法加1;
解决办法: 如果需要自增计算的话可以使用StringRedisSerializer序列化器、GenericToStringSerializer序列化器,因为他们将字符串的值直接转为字节数组,所以保存到redis中是数字,所以可以进行加1 ;
特殊情况: 如果redis中先存储了StringRedisSerializer或GenericToStringSerializer序列化之后的值,然后又在使用Jackson2JsonRedisSerializer或者JdkSerializationRedisSerializer进行自增之类的计算时仍然可用,不会报错。

本小节内容参考博客:Redis 序列化方式StringRedisSerializer、FastJsonRedisSerializer和KryoRedisSerializer
另外推荐一篇不错的博文:SpringBoot整合Redis—自定义配置

4、Redis自定义配置类
@Configuration
@SuppressWarnings({ "rawtypes", "unchecked" })
public class RedisConfig {

	@Bean(name = "redisTemplate")
	public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
		RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
		redisTemplate.setConnectionFactory(factory);

		// 设置value的序列化方式
		Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);
		ObjectMapper mapper = new ObjectMapper();
		// 可视化设置
		// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
		mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
		// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会抛出异常
		// mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);  //已经过时,用下边的设置代替
		mapper.activateDefaultTyping(
				LaissezFaireSubTypeValidator.instance,
				ObjectMapper.DefaultTyping.NON_FINAL,
				JsonTypeInfo.As.PROPERTY); 
		jacksonSeial.setObjectMapper(mapper);
		// 设置key的序列化方式,一般选用StringRedisSerializer
		redisTemplate.setKeySerializer(new StringRedisSerializer());
		// 设置value的序列化方式
		redisTemplate.setValueSerializer(jacksonSeial);

		// 设置hash key 和hash value序列化模式
		redisTemplate.setHashKeySerializer(new StringRedisSerializer());
		redisTemplate.setHashValueSerializer(jacksonSeial);
		redisTemplate.afterPropertiesSet();
		return redisTemplate;
	}
}
5、使用测试
	@Autowired
	private RedisTemplate<String, Object> redisTemplate;

	@RequestMapping(value = "/user", method = RequestMethod.GET)
	public void getUserInfo() {
		User user = new User();
		user.setName("zhangsan");
		user.setSex("男");
		user.setAge(12);
		System.out.println("user:" + user);
		redisTemplate.opsForValue().set(user.getName(), user);
		User user1 = (User) redisTemplate.opsForValue().get(user.getName());
		System.out.println("user1:" + user1);
	}

user实体类就三个字段,姓名、性别、年龄;这里就不给出了。

6、常见问题

问题1: 当使用 “Jackson2JsonRedisSerializer” 对值进行序列化,当获取数据时报如下所示的错误:

java.util.LinkedHashMap cannot be cast to com.learn.entity.Student

出现这个问题的原因是因为没有设置"DefaultTyping",当不设置这个参数时,序列化之后的数据是一个纯Json,不包含类型,设置这个参数的方式如下:

		ObjectMapper mapper = new ObjectMapper();
		// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会抛异常
		// mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);  //已经过时,用下边的设置代替
		mapper.activateDefaultTyping(
				LaissezFaireSubTypeValidator.instance,
				ObjectMapper.DefaultTyping.NON_FINAL,
				JsonTypeInfo.As.PROPERTY); 
		jackson2JsonRedisSerializer.setObjectMapper(mapper);

来看下设置以后Redis中存储的数据格式有什么不同:
设置之后

[
  "java.util.ArrayList",	// 包含类型
  [
    {
      "@class": "com.learn.entity.Student",  // 包含类型
      "id": "5f51b23d34f9c5155cda1ab4",
      "name": "张三",
      "sex": "男",
      "school": {
        "@class": "com.learn.entity.School",
        "id": "5f51b23d34f9c5155cda1ab3",
        "students": null,
        "name": "BJ_university"
      }
    }
  ]
]

设置之前

[
  {
    "id": "5f51b23d34f9c5155cda1ab4",
    "name": "张三",
    "sex": "男",
    "school": {
      "id": "5f51b23d34f9c5155cda1ab3",
      "students": null,
      "name": "BJ_university"
    }
  }
]

这样当我们获取数据时就可以直接转化为List格式的数据,方便直接使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值