将对象序列化存到redis缓存中

本文介绍了如何在Spring框架下利用@Cacheable注解实现Redis缓存,以及如何手动获取和删除缓存中的HashMap数据。在处理过程中,HashMap包含在实现了序列化接口的类中,并通过序列化方法保存到Redis缓存中。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

当前spring框架提供了完整的redis缓存的注解支持,只要在方法前面加上注解@Cacheable
直接去访问这个方法就会自动获取缓存。但是
会存在一种这样的需求就是你不想去访问这方法
就可以当前缓存中数据。 这个时候你可以自
己写方法去获取当前缓存key值的对应缓存的
数据。一下是我写的手动去获取我存在缓存中的
hashMap和删除hashMap中的数据,其中
hashmap被封装在类中,该类需要实现序列化接口,
再将该类序列化保存到缓存中。

package com.bisa.hkshop.zj.component;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import com.bisa.health.appserver.utils.CacheUtity;
import com.bisa.hkshop.zj.basic.utility.BaseDelayed;
import com.bisa.hkshop.zj.basic.utility.DelayOrderDto;

@Component
public class OrderRedisImp implements IOrderRedis{

    @Autowired
    private RedisTemplate redisTemp;

    //获取所有redis中所有的order
    @Override
    public HashMap<String,BaseDelayed<String>> getOrderRedis() {//对象换成你自己
        DelayOrderDto order;
        if(redisTemp.hasKey("order")){
                    order = (DelayOrderDto) redisTemp.execute(new RedisCallback<Object>() {
                    public Object doInRedis(RedisConnection connection) throws DataAccessException {
                        String sms_key = "order";
                        byte[] value = connection.get(sms_key.getBytes());
                        if(value.length>0){
                            return CacheUtity.toObject(value);
                        }else{
                            return "";
                        }
                    }
                });
          return  order.getDelaylist();
        }
        return null;
    }


    //添加到缓存
    public void addOrderRedis(BaseDelayed<String> delayed) { //对象是你自己的
        /**
         * 将order存到redis缓存
         */
        //对象换成你自己
        HashMap<String,BaseDelayed<String>> delayList = this.getOrderRedis();
        if(delayList==null){
            delayList = new HashMap<String,BaseDelayed<String>>();
        }
        delayList.put(delayed.getValue(), delayed);

        DelayOrderDto order = new DelayOrderDto();
        order.setDelaylist(delayList); //存到封装好的map中

        redisTemp.execute(new RedisCallback<Boolean>() {
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                String sms_key = "order";
                connection.setEx(sms_key.getBytes(), 3600, CacheUtity.toByteArray(order));
                return true;
            }
        });


    }
        //删除缓存中某个order
    public void delOrderRedis(BaseDelayed<String> delayed) {
        /*
         * 将delay从redis中的删除
         */
        HashMap<String,BaseDelayed<String>> delayList = this.getOrderRedis();
        delayList.remove(delayed.getValue());
        DelayOrderDto order = new DelayOrderDto();
        order.setDelaylist(delayList); //存到封装好的HashMap中
        redisTemp.execute(new RedisCallback<Boolean>() {
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                String sms_key = "order";
                connection.setEx(sms_key.getBytes(), 3600, CacheUtity.toByteArray(order));
                return true;
            }
        });

    }



}

下面是关于序列化的两个方法:

package com.bisa.health.appserver.utils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class CacheUtity {
    //将对象序列化
    static public byte[] toByteArray(Object obj) {
        byte[] bytes = null;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(obj);
            oos.flush();
            bytes = bos.toByteArray();
            oos.close();
            bos.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return bytes;
    }
//反序列化
    static public  Object toObject(byte[] bytes) {
        Object obj = null;
        try {
            ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
            ObjectInputStream ois = new ObjectInputStream(bis);
            obj = ois.readObject();
            ois.close();
            bis.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
        }
        return obj;
    }
}
使用 Redis 进行缓存时,对象序列化和反序列化是实现数据持久化和传输的关键步骤。Redis 本身存储的是字节流,因此需要将对象转换为可存储和传输的格式。以下介绍几种常见的方法及其实现方式。 ### 使用 JSON 序列化 JSON 是一种常用的数据交换格式,它具有可读性强、跨语言支持好等优点。常见的 JSON 序列化库包括 Jackson、Gson 和 Fastjson。 以 Jackson 为例,可以通过自定义 `RedisTemplate` 的序列化方式来实现: ```java @Configuration public class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(factory); template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); template.setHashKeySerializer(new StringRedisSerializer()); template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer()); template.afterPropertiesSet(); return template; } } ``` 这种方式将对象序列化为 JSON 格式,并在反序列化时恢复为原始对象,适用于大多数场景[^2]。 ### 使用 Protobuf 序列化 Protocol Buffers(Protobuf)是由 Google 开发的一种高效、紧凑的序列化方式,适用于对性能和存储空间有较高要求的场景。Protobuf 需要预先定义数据结构(.proto 文件),然后通过工具生成代码进行序列化和反序列化。 以下是一个简单的 Protobuf 序列化示例: ```java // 定义 .proto 文件 syntax = "proto3"; message User { string name = 1; int32 age = 2; } // 序列化 User user = User.newBuilder().setName("Alice").setAge(30).build(); byte[] data = user.toByteArray(); // 反序列化 User parsedUser = User.parseFrom(data); ``` 将 Protobuf 与 Redis 结合使用时,可以将 `RedisTemplate` 的序列化器替换为自定义的 Protobuf 序列化器,从而实现高效的数据存储和读取。 ### 使用 Kryo 序列化 Kryo 是一个高效的 Java 序列化框架,支持循环引用、压缩等特性。Kryo 的序列化速度和压缩率优于 JDK 自带的序列化方式,但其生成的字节流不具备可读性。 可以通过以下方式配置 Kryo 序列化: ```java public class KryoRedisSerializer<T> implements RedisSerializer<T> { private final Class<T> type; private final Kryo kryo = new Kryo(); public KryoRedisSerializer(Class<T> type) { this.type = type; } @Override public byte[] serialize(T t) { Output output = new Output(1024, -1); kryo.writeObject(output, t); return output.toBytes(); } @Override public T deserialize(byte[] bytes) { if (bytes == null) { return null; } Input input = new Input(bytes); return kryo.readObject(input, type); } } ``` 配置 `RedisTemplate` 使用 Kryo 序列化器: ```java @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(factory); template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(new KryoRedisSerializer<>(MyObject.class)); template.setHashKeySerializer(new StringRedisSerializer()); template.setHashValueSerializer(new KryoRedisSerializer<>(MyObject.class)); template.afterPropertiesSet(); return template; } ``` ### 使用 Avro 序列化 Apache Avro 是另一个流行的序列化框架,支持模式演化(Schema Evolution),适用于需要长期存储和兼容性要求的场景。Avro 支持多种序列化格式,包括二进制和 JSON。 Avro 的使用需要定义 `.avsc` 文件,然后通过工具生成对应的 Java 类。以下是 Avro 的基本使用方式: ```java // 序列化 User user = new User("Alice", 30); ByteArrayOutputStream out = new ByteArrayOutputStream(); DatumWriter<User> writer = new SpecificDatumWriter<>(User.class); Encoder encoder = EncoderFactory.get().binaryEncoder(out, null); writer.write(user, encoder); encoder.flush(); byte[] data = out.toByteArray(); // 反序列化 DatumReader<User> reader = new SpecificDatumReader<>(User.class); Decoder decoder = DecoderFactory.get().binaryDecoder(data, null); User parsedUser = reader.read(null, decoder); ``` 将 Avro 与 Redis 结合使用时,可以将 `RedisTemplate` 的序列化器替换为 Avro 序列化器,从而实现结构化数据的高效存储。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值