springboot整合redis详解以及对象序列化和redis工具类

一、springboot整合redis

如果redis连接不上可参考 https://blog.csdn.net/HBliucheng/article/details/112603127
1,pom引入ga坐标

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
        </dependency>

在spring2.x之后,原来使用的jedis被替换成了lettuce
jedis:采用直连,多个线程操作的话,是不安全的
lettuce:采用netty,实例可以在多个线程中进行共享,不存在线程不安全的情况

2,application.yml配置
连接超时时间可以自行设置

spring:
  redis:
    host: 192.168.119.3
    port: 6379
#    connect-timeout: 3000

3,注入redisTemplate,只用redisTemplate可以操作不同的数据类型,api和rendis命令一样的
redis常用命令可参考 https://blog.csdn.net/HBliucheng/article/details/111600127

opsForValue操作String类型
opsForList操作list类型
opsForSet操作set类型
opsForHash操作hash类型
opsForZset操作zset类型
opsForGeo操作geo类型
opsForHyperLogLog操作HyperLogLog类型
当然还有 StringRedisTemplate操作String类型
具体类和方法不做赘述,下面会提供redisUtils来操作redis。这是目前大部分公司的做法

二、redis序列化

1,redis为什么需要序列化
序列化最终的目的是为了对象可以跨平台存储,和进行网络传输。而我们进行跨平台存储和网络传输的方式就是IO,而我们的IO支持的数据格式就是字节数组
2,redis序列化方式对比
redis的默认方式是JdkSerializationRedisSerializer

JdkSerializationRedisSerializer: 使用JDK提供的序列化功能。

优点是反序列化时不需要提供类型信息(class),但缺点是需要实现Serializable接口,还有序列化后的结果非常庞大,是JSON格式的5倍左右,这样就会消耗redis服务器的大量内存。

Jackson2JsonRedisSerializer: 使用Jackson库将对象序列化为JSON字符串。

优点是速度快,序列化后的字符串短小精悍,不需要实现Serializable接口。

但缺点也非常致命,那就是此类的构造函数中有一个类型参数,必须提供要序列化对象的类型信息(.class对象)。 通过查看源代码,发现其只在反序列化过程中用到了类型信息。

问题:使用默认的JDK序列化方式,在RDM工具中查看k-v值时会出现“乱码”,不方便查看
推荐使用 Jackson2JsonRedisSerializer

3,使用默认的序列化方式 JdkSerializationRedisSerializer
** 所有对象都需要序列化**

当对象不序列化时会报错
POJO类

package com.example.redisdemo.pojo;

import lombok.*;

import java.io.Serializable;

/**
 * @author LiuCheng
 * @data 2021/1/14 13:55
 */
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class User {
    
    
    private String name;
    private int age;

}

测试类,启动发现会报错

 @Test
    void test3(){
    
    
        User user = new User("张三", 12);
        redisTemplate.opsForValue().set("user",user);
        System.out.println(redisTemplate.opsForValue().get("user"));
    }

在这里插入图片描述
所以所有对象类存入redis时需要序列化,加上序列化后(实现 Serializable )再运行下test

package com.example.redisdemo.pojo;

import lombok.*;

import java.io.Serializable;

/**
 * @author LiuCheng
 * @data 2021/1/14 13:55
 */
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class User implements Serializable {
    
    
    private String name;
    private int age;

}

再次运行 ,正常运行,结果也能取出来
在这里插入图片描述

4,自定义序列化方式序列化 Jackson2JsonRedisSerializer。自定义redisTemplate*

package com.example.redisdemo.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * @author LiuCheng
 * @data 2021/1/14 14:25
 */
@Configuration
public class RedisConfig {
    
    
    @Bean
    public RedisTemplate<String,Object>  redisTemplate(RedisConnectionFactory factory){
    
    
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);

        // 老方法已过期舍弃
//        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        objectMapper.enable(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key 采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);

        //hash 的key采用String 的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        // hash 的value 采用jackson方式序列化
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        // value采用String的序列化方式
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return  template;
    }
}

POJO类(未实现Serializable 接口)

package com.example.redisdemo.pojo;

import lombok.*;

import java.io.Serializable;

/**
 * @author LiuCheng
 * @data 2021/1/14 13:55
 */
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class User  {
    
    
    private String name;
    private int age;

}

测试类
此处有个小bug,在String类型中放入key后,后在Hash中放入相同的key会报错,只需要删除key后再次放入即可
https://blog.csdn.net/HBliucheng/article/details/112610780

@Test
    void test3(){
    
    
        User user = new User("张三", 12);
        redisTemplate.opsForValue().set("user",user);
        System.out.println(redisTemplate.opsForValue().get("user"));
        // 移除key否则下面再次添加user时会报错
        redisTemplate.delete("user");
        redisTemplate.opsForHash().put("user","2",user);
        System.out.println(redisTemplate.opsForHash().get("user", "2"));
    }

运行结果
在这里插入图片描述

redisUtils工具类 https://blog.csdn.net/HBliucheng/article/details/112614392

猜你喜欢

转载自blog.csdn.net/HBliucheng/article/details/111824877
今日推荐