前言
感觉StringRedisTemplate和RedisTemplate非常的相识,到底有什么区别和联系呢?点开idea,打开其依赖关系,可以看出只需使用maven依赖包spring-boot-starter-data-redis,然后在service中注入StringRedisTemplate或者RedisTemplate即可使用。
从下图StringRedisTemplate继承了RedisTemplate,所以两者对Redis的操作方法具有相同之处
实验软件:RedisDesktopManager
RedisTemplate
RedisTemplate使用的是JdkSerializationRedisSerializer存入数据,会将数据先序列化成字节数组,然后在存入Redis数据库。
如果数据是复杂的对象类型,而取出的时候又不想做任何的数据转换,直接从Redis里面取出一个对象,那么使用RedisTemplate是更好的选择。
你会看到你的数据不是以可读的形式展现的,而是以字节数组显示,类似下面
当然从Redis获取数据的时候,也会默认将数据当做字节数组转化,这样就会导致一个问题,当需要获取的数据,不是以字节数组存在redis当中,而是正常的可读的字符串的时候,比如说下面这种形式的数据
RedisTemplate就无法获取导数据,这个时候获取到的值就是NULL。这个时候StringRedisTempate就派上了用场。
StringRedisTemplate
源码是:
package org.springframework.data.redis.core;
import org.springframework.data.redis.connection.DefaultStringRedisConnection;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
public class StringRedisTemplate extends RedisTemplate<String, String> {
public StringRedisTemplate() {
RedisSerializer<String> stringSerializer = new StringRedisSerializer();
this.setKeySerializer(stringSerializer);
this.setValueSerializer(stringSerializer);
this.setHashKeySerializer(stringSerializer);
this.setHashValueSerializer(stringSerializer);
}
public StringRedisTemplate(RedisConnectionFactory connectionFactory) {
this();
this.setConnectionFactory(connectionFactory);
this.afterPropertiesSet();
}
protected RedisConnection preProcessConnection(RedisConnection connection, boolean existingConnection) {
return new DefaultStringRedisConnection(connection);
}
}
StringRedisTemplate使用的是StringRedisSerializer,当你的redis数据库里面本来存的是字符串数据,或者你要存取的数据就是字符串类型数据的时候,那么你就使用StringRedisTemplate即可。
当redis中存入的数据是可读形式而非字节数组时,使用redisTemplate取值的时候会无法获取导出数据,获得的值为null。可以使用 StringRedisTemplate 试试。
StringRedisTemplate对于Redis的操作方法:
StringRedisTemplate.opsForValue().* //操作String字符串类型
StringRedisTemplate.delete(key/collection) //根据key/keys删除
StringRedisTemplate.opsForList().* //操作List类型
StringRedisTemplate.opsForHash().* //操作Hash类型
StringRedisTemplate.opsForSet().* //操作set类型
StringRedisTemplate.opsForZSet().* //操作有序set
在生产环境中想通用StringRedisTemplate和RedisTemplate
混合使用问题
下面先看一个单元测试:
@Slf4j
@SpringBootTest
class RedisDifferentTemplateTest {
@Resource
private RedisTemplate<String, Object> redisTemplate;
@Resource
private StringRedisTemplate stringRedisTemplate;
@Test
void testSimple() {
redisTemplate.opsForValue().set("baidu", "www.jenkins_baidu.com");
Assertions.assertEquals("www.jenkins_baidu.com", redisTemplate.opsForValue().get("baidu"));
Assertions.assertEquals("www.jenkins_baidu.com",stringRedisTemplate.opsForValue().get("baidu"));
}
}
在上述方法中先通过redisTemplate存储一个key为baidu的数据到Redis中,随后通过redisTemplate获取并判断断言,可以成功通过。但随后通过stringRedisTemplate获取同样的key的值,则抛出异常,异常信息如下:
org.opentest4j.AssertionFailedError:
Expected :www.jenkins_baidu.com
Actual :null
<Click to see difference>
也就是说获取的结果为null,也就是说StringRedisTemplate只能管理StringRedisTemplate里面的数据,RedisTemplate只能管理RedisTemplate中的数据。
StringRedisTemplate取不到RedisTemplate里面的数据。
那么,我们再通过Redis客户端看一下两种形式存储到redis中key的值的情况。
可以看到通过StringRedisTemplate存储的数据Key为“myWeb”,而RedisTemplate存储的Key为“\xAC\xED\x00\x05t\x00\x05myWeb”,这也就是为什么默认情况下两者存储的数据没办法混合使用了。
在生产环境中想通用StringRedisTemplate和RedisTemplate进行字符串的处理该怎么办?
解决方案
此时就需要指定统一的Key与Value的序列化处理类,比如在RedisTemplate序列化时,指定与StringRedisTemplate相同的默认的序列化类,进行统一修改。
@BeforeEach
void init() {
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
}
在configuration中配置redisSessionTemplate,注意几个Serializer的配置,不匹配会导致读取出错
@Bean
public <K,V> RedisTemplate<K, V> redisSessionTemplate(RedisConnectionFactory factory) {
RedisTemplate<K, V> template = new RedisTemplate<>();
// 配置连接工厂
template.setConnectionFactory(factory);
//JdkSerializationRedisSerializer jdkRedisSerializer = new JdkSerializationRedisSerializer();
RedisSerializer<String> keySerializer = new StringRedisSerializer();
RedisSerializer<Object> valueSerializer = new JdkSerializationRedisSerializer(
this.getClass().getClassLoader());
// 值采用json序列化
template.setValueSerializer(valueSerializer);
//使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(keySerializer);
// 设置hash key 和value序列化模式
template.setHashKeySerializer(keySerializer);
template.setHashValueSerializer(valueSerializer);
template.afterPropertiesSet();
return template;
}
………………………………
String sessionKey ="spring:session:sessions:" + sessionId;
redisSessionTemplate.opsForHash().get(sessionKey, "sessionAttr:currentUser");
redisSessionTemplate.opsForHash().get(sessionKey, "sessionAttr:loginAccount");