在SpringBoot中,经常使用RedisTemplate来对redis进行操作,但是我们会发现,当我们修改了RedisTemplate的序列化方式之后,在存取Long类型数据时,会发生一些问题。
前置知识点:SpringBoot之RedisTemplate操作redis出现\xAC\xED\x00\x05t\x00\x08乱码问题
问题:
当我们定义了一个Long类型的数据l1,且l1的实际值小于等于 Integer.MAX_VALUE 时。这个时候将l1存入redis再从redis中重新读取l1的值时,如果使用了(Long)进行类型转换时,也就是下方代码:
(Long) redisTemplate.opsForValue().get(k1)
会直接报异常:java.lang.Integer cannot be cast to java.lang.Long
那么问题来了,我明明存进去的是个Long类型,为啥取出来的时候变成了Integer类型呢?
原因是因为我们指定了RedisTemplate的序列化方式,实际在redis存的是具体的数字,那么当读取的时候,代码并不知道缓存中的数字到底是Integer类型还是Long类型,于是乎会使用实际数字的值进行自动转换。
那我们有什么办法可以解决这个问题呢?除了使用Object对象进行缓存结果的承接,然后判断类型进行转换,有没有什么更好的办法?
我们仔细观察一下Integer类和Long类,会发现他们都继承了一个Number类,而且Number类中存在intValue()和longValue() 两个方法。那么问题就迎刃而解了,我们可以直接使用(Number)进行类型转换,在需要使用的地方用具体的xxValue()方法进行值的获取即可。
测试代码:
//往缓存写入数据
Long l1 = 1L;
Long l2 = Integer.MAX_VALUE + 1L;
String k1 = "k1";
String k2 = "k2";
redisTemplate.opsForValue().set(k1, l1);
redisTemplate.opsForValue().set(k2, l2);
//从缓存中读取数据
Object o1 = redisTemplate.opsForValue().get(k1);
Object o2 = redisTemplate.opsForValue().get(k2);
System.out.println("k1对应value类型"+o1.getClass().getName());
System.out.println("k2对应value类型"+o2.getClass().getName());
//强制使用Long类型会报异常
try {
Long o3 = (Long) redisTemplate.opsForValue().get(k1);
} catch (Exception e) {
System.out.println(e.getMessage());
}
//解决方法
Number n1 = (Number) redisTemplate.opsForValue().get(k1);
System.out.println("需要int时"+n1.intValue());
System.out.println("需要long时"+n1.longValue());
代码:https://gitee.com/lqccan/blog-demo/tree/master/SpringBoot/redis-number
单元测试:DemoApplicationTest