redis:存储对象的解决方法,序列化器的设置

redis:存储对象的解决方法,序列化器的设置

注意

commands代表RedisCommands commands = RedisUtils.getCommands();
Product实体类:

@Data
public class Product implements Serializable {
    private String productName;
    private String place;
    private String firm;
}

JSON格式的字符串

只需要把对象转换成JSON格式的字符串并存储到数据库中,获取反之
缺点:对象信息容易丢失

Product p = new Product();
p.setProductName("name");
p.setFirm("apple inc");
p.setPlace("china");
commands.set("Product:1001", JSONUtil.toJsonStr(p));
log.info("===>" + JSONUtil.toBean((String) commands.get("Product:1001"),Product.class));

使用Maven依赖(不需要特定的工具只需要JSON转换可以了)

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.16</version>
</dependency>

效果

file

字节数组(自定义序列化器)

/**
 * 当对象在I/O流中传输时,这个对象必须实现Serializable接口
 */
public class ObjectRedisSerializer implements RedisCodec<String, Object> {
    /**
     * 这个方法将key从redis取出来的时候转换成字符串类型
     * 将key的字节缓冲(ByteBuffer)转换成string类型
     *
     * @param bytes Raw bytes of the key, must not be {@literal null}.
     * @return
     */
    @Override
    public String decodeKey(ByteBuffer bytes) {
        // 在系统中分配内存,(为什么需要分配,8GB的内存条中有JVM的空间[用于运行java],Redis是另一个空间,JVM无法直接读取,需要创建一个额外的空间读取)
        ByteBuffer buffer = ByteBuffer.allocate(bytes.capacity());
        buffer.put(bytes);
        // 将字节数组以UTF-8的编码转换成String并返回
        return new String(buffer.array(), StandardCharsets.UTF_8);
    }

    /**
     * 从redis取出来的字节数组转换成任意的Object对象
     *
     * @param bytes Raw bytes of the value, must not be {@literal null}.
     * @return
     */
    @Override
    public Object decodeValue(ByteBuffer bytes) {
        // 在系统中分配内存
        ByteBuffer buffer = ByteBuffer.allocate(bytes.capacity());
        buffer.put(bytes);
        // 构建字节数组的输入流,这样就可以在JVM的内存中将这个字节数组反序列化成任意的Object对象
        try (ByteArrayInputStream bais = new ByteArrayInputStream(buffer.array())) {
            // 再通过对象输入流将其转换即可
            ObjectInputStream ois = new ObjectInputStream(bais);
            return ois.readObject();
        } catch (IOException | ClassNotFoundException e) {
            throw new RuntimeException("无法反序列化value", e);
        }
    }

    /**
     * 字符串的key序列化成字节数组保存到redis
     * @param key the key, may be {@literal null}.
     *
     * @return
     */
    @Override
    public ByteBuffer encodeKey(String key) {
        return ByteBuffer.wrap(key.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * Object序列化成字节数组保存到redis
     * @param value the value, may be {@literal null}.
     *
     * @return
     */
    @Override
    public ByteBuffer encodeValue(Object value) {
        // 构建字节数组的输出流
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            // 将对象写入流中变成字节数组
            oos.writeObject(value);
            // 从流中获取字节数组
            byte[] bytes = baos.toByteArray();
            // 将字节数组包装成ByteBuffer对象并返回
            return ByteBuffer.wrap(bytes);
        } catch (IOException e) {
            throw new RuntimeException("无法序列化object", e);
        }
    }
}

效果

file

Spring中装配

装配String类型的RedisTemplate

装配String类型的RedisTemplate,用于操作redis数据库,这个template只能用于操作key和value都是String类型的数据

@Bean
public RedisTemplate<String,String> stringRedisTemplate(){
    // 创建StringRedisTemplate并注入连接工厂
    return new StringRedisTemplate(connectionFactory());
}

装配自定义的RedisTemplate(推荐)

市场推荐使用这种方法
装配自定义的RedisTemplate,通过使用不同的序列化器,来定制序列化key和value的数据类型

@Bean
public RedisTemplate<String,Object> redisTemplate(){
    RedisTemplate<String,Object> template = new RedisTemplate();
    // 使用StringRedisSerializer来序列化和反序列化key
    template.setKeySerializer(RedisSerializer.string());
    template.setHashKeySerializer(RedisSerializer.string());
    // 使用Jackson序列化器来序列化和反序列化value
    // 底层使用 js序列化 的包
    template.setValueSerializer(RedisSerializer.json());
    template.setHashValueSerializer(RedisSerializer.json());
    // 注入RedisConnectionFactory
    template.setConnectionFactory(connectionFactory());
    return template;
}

效果

file