RedisTemplate和StringRedisTemplate在项目中应用

一,应用场景:项目启动时,需要进行初始化,初始化内容为redis缓存,目的是数据提前加载到缓存,而不是在项目中查询用到了,再去查询数据库,初始化缓存

初始化实现逻辑:清空缓存,查询数据库,初始化redis及本地缓存。

二,实现

项目中redis存储的数据类型有两种,一种是String,一种是对象类型数据

String类型数据,使用StringRedisTemplate类

对象类型数据,用RedisTemplate

为啥这样参考:

https://blog.csdn.net/notsaltedfish/article/details/75948281

我参考完之后,也没太十分明白,String类型用StringRedisTemplate就行了,原因是直接保存,直接取出来没问题,不会为null啥的

重点说一下:保存对象类型用RedisTemplate

在项目中,需要把对象先序列化为字节数据,保存起来,取的时候,取得是字节数据,再反序列化为可见的对象,(我就想为什么还要进行序列及反序列操作,不能拿过来直接用吗,可以,见下文)实现如下

存:

保存数据:
ValueOperations<String,byte[]> operations = redisTemplate.opsForValue();
operations.set(CacheKeyEnum.DOCUMENT.getKey()+apiDocument.getMethod(), ProtoStuffUtils.serialize(apiDocument));

取:

  BoundValueOperations<String, byte[]> operationsGet = redisTemplate.boundValueOps(CacheKeyEnum.DOCUMENT.getKey() + apiDocument.getMethod());
        if (operationsGet.get() != null) {
            byte[] bytes = operationsGet.get();
            apiDocument = ProtoStuffUtils.deSerialize(bytes, ApiDocument.class);
        }

序列化:

/**
 * 序列化,保存对象到redis
 * @author lr
 * @date 2019-07-30 11:40
 */
public class ProtoStuffUtils {

    /**
     * 序列化
     * @param message
     * @return
     */
    public static <T> byte[] serialize(T message) {
        Class<T> cls = (Class<T>) message.getClass();
        LinkedBuffer linkedBuffer = LinkedBuffer.allocate();
        Schema<T> schema =  RuntimeSchema.getSchema(cls);
        byte[] bytes = ProtostuffIOUtil.toByteArray(message,schema, linkedBuffer);
        return bytes;
    }

    /**
     * 反序列化
     * @param bytes
     * @return
     */
    public static <T> T deSerialize(byte[] bytes,Class<T> cls) {
        T message = null;
        try {
            message = cls.newInstance();
            ProtostuffIOUtil.mergeFrom(bytes,message, RuntimeSchema.getSchema(cls));
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        return message;
    }
}

三,优化

上文提到为什么还要进行序列及反序列操作,不能拿过来直接用吗,项目中这样做是因为对象本身没有实现序列化接口,我尝试了一下,对象实现序列化接口,就可以不用序列化操作,实现如下

基类添加序列化
public class ApiDocument extends BaseEntity
public class BaseEntity implements Serializable {
存:
ValueOperations<String, ApiDocument> operations = redisTemplate.opsForValue();
ApiDocument apiDocument = apiDocuments.get(0);
operations.set(CacheKeyEnum.DOCUMENT.getKey() + apiDocument.getMethod(), apiDocument);
取:
BoundValueOperations<String, ApiDocument> operationsObj = redisTemplate.boundValueOps(CacheKeyEnum.DOCUMENT.getKey() + apiDocument.getMethod());
ApiDocument apiDocument1 = operationsObj.get();

四,项目初始化代码


/**
 * 初始化缓存(本地和Redis)
 * @author lr
 * @date 2019-07-26 16:05
 */
public class InitLocalRedisCache implements InitializingBean {


    private RedisTemplate redisTemplate;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private ApiProjectMapper apiProjectMapper;

    @Autowired
    private ApiDocumentMapper apiDocumentMapper;

    @Autowired
    private AppMapper appMapper;

    public InitLocalRedisCache(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 设置redis key的序列化方式为字符串
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        redisTemplate.setKeySerializer(new StringRedisSerializer(StandardCharsets.UTF_8));
    }

    /**
     * 初始化redis缓存。加载时先清空缓存
     */
    public void init(){
        ValueOperations<String,byte[]> operations = redisTemplate.opsForValue();
        ValueOperations<String, String> valueOperations = stringRedisTemplate.opsForValue();

        //1、清空缓存
        clearLocalRedisCache();

        //2、缓存项目服务地址
        List<ApiProject> apiProjects = apiProjectMapper.selectList(null);
        apiProjects.stream().forEach(apiProject -> {
            valueOperations.set(CacheKeyEnum.PROJECT.getKey()+apiProject.getProjectCode(), apiProject.getProductUrl());
            LocalCache.OPEN_PROJECT_URL_CACHE.put(apiProject.getProjectCode(),apiProject.getProductUrl());
        });

        //3、缓存接口信息(已发布)
        List<ApiDocument> apiDocuments = apiDocumentMapper.selectList(new QueryWrapper<ApiDocument>()
                .eq(GatewayConstant.STATUS, GatewayConstant.METHOD_PUBLISHED));

        apiDocuments.stream().forEach(apiDocument -> {
            operations.set(CacheKeyEnum.DOCUMENT.getKey()+apiDocument.getMethod(), ProtoStuffUtils.serialize(apiDocument));
            LocalCache.OPEN_DOCUMENT_CACHE.put(apiDocument.getMethod(),apiDocument);
        });

        //4、缓存应用秘钥
        List<OpenApp> openApps = appMapper.selectList(new QueryWrapper<OpenApp>().eq(GatewayConstant.STATUS, GatewayConstant.ENABLE));
        openApps.stream().forEach(openApp -> {
            valueOperations.set(CacheKeyEnum.APP.getKey()+openApp.getAppId(), openApp.getAppSecret());
            LocalCache.OPEN_APP_SECRET_CACHE.put(openApp.getAppId(),openApp.getAppSecret());
        });
    }

    /**
     * 清空缓存
     */
    private void clearLocalRedisCache() {
        //应用秘钥缓存
        Set appRedis = redisTemplate.keys(CacheKeyEnum.APP.getKey() + "*");
        redisTemplate.delete(appRedis);

        //项目服务地址缓存
        Set projectUrls = redisTemplate.keys(CacheKeyEnum.PROJECT.getKey() + "*");
        redisTemplate.delete(projectUrls);

        //接口详情缓存
        Set documents = redisTemplate.keys(CacheKeyEnum.DOCUMENT.getKey() + "*");
        redisTemplate.delete(documents);
    }
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值