加入依赖
<!--junit-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!--redis 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
注入工厂方法
注入一个redis连接的factor bean。(Redis连接工厂会生成到Redis数据库服务器的连接)
@Configuration
public class RedisConfig {
/*注入工厂类*/
@Bean
public RedisConnectionFactory redisCF(){
//如果什么参数都不设置,默认连接本地6379端口
JedisConnectionFactory factory = new JedisConnectionFactory();
factory.setPort(6379);
factory.setHostName("localhost");
return factory;
}
}
单元测试,使用这个工厂方法
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
public class RedisTest {
private Logger LOGGER = LoggerFactory.getLogger(this.getClass());
@Autowired
RedisConnectionFactory factory;
@Test
public void testRedis(){
//得到一个连接
RedisConnection conn = factory.getConnection();
conn.set("hello".getBytes(), "world".getBytes());
System.out.println(new String(conn.get("hello".getBytes())));
}
}
使用redistemplate
Spring Data Redis提供了两个模板: RedisTemplate StringRedisTemplate
首先我们先创建一个RedisTemplate模板类,类型的key是String类型,value是Object类型(如果key和value都是String类型,建议使用StringRedisTemplate)
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory factory){
//创建一个模板类
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
//将刚才的redis连接工厂设置到模板类中
template.setConnectionFactory(factory);
return template;
}
单元测试
@Autowired
RedisTemplate<String, Object> template;
@Test
public void testRedisTemplate(){
template.opsForValue().set("key1", "value1");
System.out.println(template.opsForValue().get("key1"));
}
值的一说的是插入的hash类型的key前面会有一堆的\xac\xed\x00\x05t\x00\ 这种东西 见上图 分析spring-data的org.springframework.data.redis.core.RedisTemplate源代码以后发现:
if(this.defaultSerializer == null) {
this.defaultSerializer = new JdkSerializationRedisSerializer(this.classLoader != null?this.classLoader:this.getClass().getClassLoader());
}
因为spring操作redis是在jedis客户端基础上进行的,而jedis客户端与redis交互的时候协议中定义是用byte类型交互,jedis中提供了string类型转为byte[]类型,但是看到spring-data-redis中RedisTemplate<K, V>在操作的时候k,v是泛型的,所以RedisTemplate中有了上面那段代码,在没有特殊定义的情况下,spring默认采用defaultSerializer = new JdkSerializationRedisSerializer();来对key,value进行序列化操作,在经过查看JdkSerializationRedisSerializer中对序列化的一系列操作,发现如下代码:
public JdkSerializationRedisSerializer() {
this(new SerializingConverter(), new DeserializingConverter());
}
public byte[] serialize(Object object) {
if(object == null) {
return SerializationUtils.EMPTY_ARRAY;
} else {
try {
return (byte[])this.serializer.convert(object);
} catch (Exception var3) {
throw new SerializationException("Cannot serialize", var3);
}
}
}
跟踪 SerializingConverter
public byte[] convert(Object source) {
ByteArrayOutputStream byteStream = new ByteArrayOutputStream(1024);
try {
this.serializer.serialize(source, byteStream);
return byteStream.toByteArray();
} catch (Throwable var4) {
throw new SerializationFailedException("Failed to serialize object using " + this.serializer.getClass().getSimpleName(), var4);
}
}
原因其实就出现在这里的序列化
redis的序列化
当保存一条数据的时候,key和value都要被序列化成json数据,取出来的时候被序列化成对象,key和value都会使用序列化器进行序列化,spring data redis提供多个序列化器
- GenericToStringSerializer:使用Spring转换服务进行序列化;
- JacksonJsonRedisSerializer:使用Jackson 1,将对象序列化为JSON;
- Jackson2JsonRedisSerializer:使用Jackson 2,将对象序列化为JSON;
- JdkSerializationRedisSerializer:使用Java序列化;
- OxmSerializer:使用Spring O/X映射的编排器和解排器(marshaler和unmarshaler)实 现序列化,用于XML序列化;
- StringRedisSerializer:序列化String类型的key和value。
RedisTemplate会默认使用JdkSerializationRedisSerializer,这意味着key和value都会通过Java进行序列化。StringRedisTemplate默认会使用StringRedisSerializer 对刚才的redistenplate 进行修改加入key和value的序列化
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
// 创建一个模板类
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
// 将刚才的redis连接工厂设置到模板类中
template.setConnectionFactory(factory);
// 设置key的序列化器
template.setKeySerializer(new StringRedisSerializer());
// 设置value的序列化器
//使用Jackson 2,将对象序列化为JSON
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
//json转对象类,不设置默认的会将json转成hashmap
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setValueSerializer(jackson2JsonRedisSerializer);
return template;
}
测试
@Test
public void testRedisTemplateList(){
Cat tom = new Cat(1, 2, "tom");
Cat jerry = new Cat(2, 3, "jerry");
//依次从尾部添加元素
template.opsForList().rightPush("cats", tom);
template.opsForList().rightPush("cats", jerry);
//查询索引0到商品总数-1索引(也就是查出所有的商品)
List<Object> prodList = template.opsForList().range("cats", 0,template.opsForList().size("cats")-1);
for(Object obj:prodList){
System.out.println(obj);
}
System.out.println("cat的数量:"+template.opsForList().size("cats"));
}
注意:本文归作者所有,未经作者允许,不得转载