项目之使用redis的一些规范和优化

本文介绍了在项目中遇到的Redis使用问题,包括不统一的键命名导致的困扰,以及解决方案——采用模板模式,根据对象类名设置统一的前缀。通过定义接口和抽象实现类,为不同对象创建特定的Key类,简化了缓存管理和查找,提高了代码的规范性和可维护性。

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

前段时间在回顾自己项目的时候发现了一些问题,并对这些问题进行了优化,今天就来记录一下对redis使用的一些优化

redis一般情况来说用作缓存,会存储一些需要缓存的对象信息,但是当存储的内容过多以后,如何命名这些缓存的对象,能够快速地查找出你需要的对象,快速地区分哪些key里面存的是你想要的数据就成了一个问题。

举个例子:可能你今天码代码的时候觉得当存放user对象时key值应该是“user“,过几天回过头来继续写的时候又觉得key值应该写成“USER”,这个时候你还要去查找你上次写的代码的地方,和你原来书写的值做一个统一,统一这种缓存存值的命名规范,感觉是一种无脑操作,浪费时间浪费精力,还经常想当然地把命名搞错了,及其不方便

并且还会出现你查看缓存的时候可能根本不忘了这个缓存key是用来缓存什么东西了,他是属于哪个类的都不知道

这样极大地增加了自己的工作量,并且不够严谨

当时做这个项目的时候不觉得有什么问题,但是这次的目的是为了优化代码结构,写出一个规范的漂亮的不冗余的代码,这个问题就需要解决了。


我的解决方式也狠简单,使用了模板模式,针对存放对象的类不同来统一加上类名作为前缀,并且后面跟上自己自定义的名字,然后根据每一个自己想缓存的对象的所属的类去实现不同的构造名字的方法:

第一步:首先定义了一个接口,里面呢包含两个方法,设置过期时间和前缀名:

public interface KeyPrefix {
    public int expireSeconds();
    public  String getPrefix();
}

接着是一个抽象的实现类实现这两个方法:

public abstract class BasePrefix implements KeyPrefix {
    private int expireSeconds;
    private String prefix;
    public BasePrefix(int expireSeconds,String prefix)
    {
        this.expireSeconds=expireSeconds;
        this.prefix=prefix;
    }
    public BasePrefix(String prefix)
    {
        this(0,prefix);
    }

    @Override
    public int expireSeconds() {
        return expireSeconds;
    }

    @Override
    public String getPrefix() {
       String className=getClass().getSimpleName();
       return className+":"+prefix;
    }
}

后面继承这个方法的自定义方法可以使用已经实现好的方法,也可以重写这两个方法

我举个例子,你可以设置一个专门存放User对象的Key的类,里面声明后一些常用的key,这样使用起来很简单明了,当然也可以使用设置过期时间和前缀名的方法来设置缓存:

像下面这个针对User对象的key类就设置了三个默认的缓存前缀,里面分别写好了前缀名和过期时间

public class UserKey extends BasePrefix {
    public static  final int TOKEN_EXPIRE=3600*24*2;
    public static  final int FORGET_TOKEN_EXPIRE=300;
    public static  final int CURRENT_TOKEN_EXPIRE=300;
    private UserKey(int expireSeconds,String prefix)
    {
        super(expireSeconds,prefix);
    }
    public static UserKey token=new UserKey(TOKEN_EXPIRE, "tk");
    public static  UserKey forgettoken=new UserKey(FORGET_TOKEN_EXPIRE,"forgetTk");
    public static UserKey currentToken=new UserKey(CURRENT_TOKEN_EXPIRE, "currentTk");
}

写完前缀名和过期时间相关后,还需要对redisService进行修改:

1get方法:

/**
     * 获取单个对象
     */
    public  <T>T get(KeyPrefix prefix,String key,Class<T>clazz)
    {
        Jedis jedis =null;
        try{
            jedis=jedisPool.getResource();
            String realKey=prefix.getPrefix()+key;
            String str=jedis.get(realKey);

            T t =stringToBean(str,clazz);
            return t;
        }
        finally {
            returnToPool(jedis);
        }
    }

2set方法:

/**
     *设置对象
     */
    public <T> boolean set(KeyPrefix prefix,String key,T value)
    {
        Jedis jedis =null;
        try
        {
            jedis=jedisPool.getResource();
            String realKey=prefix.getPrefix()+key;
            String str=beanToString(value);
            if(str==null||str.length()<=0)
            {
                return false;
            }
            int seconds=prefix.expireSeconds();
            if(seconds<=0){
                jedis.set(realKey,str);
            }else
            {
                jedis.setex(realKey,seconds,str);
            }
           return true;
        }
        finally {
            returnToPool(jedis);
        }
    }

3 exist方法:

/**
     * 判断key是否存在
     * */
    public <T> boolean exists(KeyPrefix prefix,String key){
        Jedis jedis=null;
        try{
            jedis=jedisPool.getResource();
            String realKey=prefix.getPrefix()+key;
            return jedis.exists(realKey);
        }
        finally {
            returnToPool(jedis);
        }
    }

4 删除方法:

/**
     * 删除
     * */
    public boolean delete(KeyPrefix prefix, String key) {
        Jedis jedis =null;
        try{
            jedis=jedisPool.getResource();
            String realKey=prefix.getPrefix()+key;
            long res=jedis.del(realKey);
            return res>0;
        }
        finally {
            returnToPool(jedis);
        }
    }

5 原子自增:

/**
     * 自增
     * */
    public <T> Long incr(KeyPrefix prefix, String key) {
        Jedis jedis = null;
        try {
            jedis =  jedisPool.getResource();
            //生成真正的key
            String realKey  = prefix.getPrefix() + key;
            return  jedis.incr(realKey);
        }finally {
            returnToPool(jedis);
        }
    }

6 原子自减:

/**
     * 自减
     * */
    public <T> Long decr(KeyPrefix prefix, String key) {
        Jedis jedis = null;
        try {
            jedis =  jedisPool.getResource();
            //生成真正的key
            String realKey  = prefix.getPrefix() + key;
            return  jedis.decr(realKey);
        }finally {
            returnToPool(jedis);
        }
    }
7 对象序列化的函数:
public static <T> String beanToString(T value) {
        if(value == null) {
            return null;
        }
        Class<?> clazz = value.getClass();
        if(clazz == int.class || clazz == Integer.class) {
            return ""+value;
        }else if(clazz == String.class) {
            return (String)value;
        }else if(clazz == long.class || clazz == Long.class) {
            return ""+value;
        }else {
            return JSON.toJSONString(value);
        }
    }

8 反序列化:

public static <T> T stringToBean(String str, Class<T> clazz) {
        if(str == null || str.length() <= 0 || clazz == null) {
            return null;
        }
        if(clazz == int.class || clazz == Integer.class) {
            return (T)Integer.valueOf(str);
        }else if(clazz == String.class) {
            return (T)str;
        }else if(clazz == long.class || clazz == Long.class) {
            return  (T)Long.valueOf(str);
        }else {
            return JSON.toJavaObject(JSON.parseObject(str), clazz);
        }
    }

9 释放Jedis对象回连接池:

private void returnToPool(Jedis jedis) {
        if(jedis != null) {
            jedis.close();
        }
    }

还有很多的一些redis操作都可以自己去按照我的这个样子去重写,我就不一一列举出来了

大家会发现这样我们在redis中存放东西很清晰明了地知道命名方式和用途,如果有不足的地方请指正











评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值