SpringBoot 集成 redis - 立flag网

SpringBoot 集成 redis

加入依赖

    <!--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())));
    }
}

mark

使用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"));
    }

mark

值的一说的是插入的hash类型的key前面会有一堆的\xac\xed\x00\x05t\x00\ 这种东西 见上图 分析spring-data的org.springframework.data.redis.core.RedisTemplate源代码以后发现:

mark

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"));

    }

mark mark


已有 0 条评论

    我有话说: