【SpringBoot商城秒杀系统项目实战07】通用缓存Key的设计与封装

项目模块增多,缓存需求增加,为避免id重复引发系统错误,使用KeyPrefix操作和管理缓存key,将前缀与key组合作为Redis真正的key,可防止key冲突。还采用模板模式封装,定义BasePrefix抽象类,不同模块前缀类继承它,可按需设置key有效期。

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

为什么要这个通用缓存Key?
当项目中的模块越来越多的时候,需要存的缓存也越来越多,比如商品Id,订单Id,用户id等,此时若是id出现重复,将给系统带来错误。

那么使用KeyPrefix来更好的操作和管理缓存中对应的key。给不同模块的key带有一个前缀。

不加前缀的情况:


	public <T> boolean set(String key,T value){
		Jedis jedis=null;
		//在JedisPool里面取得Jedis
		try {
			jedis=jedisPool.getResource();
			//将T类型转换为String类型
			String s=beanToString(value);
			if(s==null) {
				return false;
			}
			jedis.set(key, s);
			return true;
		}finally {
			returnToPool(jedis);
		}
	}

解决覆盖key的办法:
将前缀+一个key一起作为一个redis里面真正的key,这样不同模块之间就不会重复。
好处:不同功能或者不同模块的前缀不同,即使有同名key出现,那么前缀不同,并不会引起key冲突被其他功能覆盖的情况。

使用一个模板模式来封装:
在这里插入图片描述
接口:

/**
 *做缓存的前缀接口 
 */
	public interface KeyPrefix {
	//有效期
	public int expireSeconds();
	//前缀
	public String getPrefix();
}

BasePrefix 抽象类:简单的实现一下KeyPrefix,定义成抽象类原因,防止不小心被创建,我们不希望BasePrefix被实例化,因为抽象类不允许实例化。我们只希望它被继承。不同模块的前缀类都继承他。

	//定义成抽象类
	public abstract class BasePrefix implements KeyPrefix{
	private int expireSeconds;
	private String prefix;
	public BasePrefix() {
	}
	public BasePrefix(String prefix) {
		//this(0, prefix);//默认使用0,不会过期
		this.expireSeconds=0;
		this.prefix=prefix;		
	}
	public BasePrefix(int expireSeconds,String prefix) {//覆盖了默认的构造函数
		this.expireSeconds=expireSeconds;
		this.prefix=prefix;
	}
	//默认为0代表永不过期
	public int expireSeconds() {
		return expireSeconds;
	}
	//前缀为类名:+prefix
	public String getPrefix() {
		String className=getClass().getSimpleName();
		return className+":"+prefix;
	}
	
}

注意:该类2种不同构造方法:用于继承。一个只带前缀名,一个带前缀名和过期时间。当实现public BasePrefix(String prefix)的时候,我们将默认这个key不会失效,因为有一些场景,我们不希望key失效,但是有些场景我们需要设置key的合适的有效期。

具体实现类:
用户UserKey只去继承了super(prefix),即public BasePrefix(String prefix),那么代表user的key的过期时间为不会过期。

	public class UserKey extends BasePrefix{
	public UserKey(String prefix) {
		super(prefix);
	}
	public static UserKey getById=new UserKey("id");
	public static UserKey getByName=new UserKey("name");
}

秒杀用户的MiaoshaUserKey ,继承了super(expireSeconds,prefix),可以设置有效期时间为2天。

	public class MiaoshaUserKey extends BasePrefix{
	public static final int TOKEN_EXPIRE=3600*24*2;//3600S*24*2    =2天
	public MiaoshaUserKey(int expireSeconds,String prefix) {
		super(expireSeconds,prefix);
	}
	public static MiaoshaUserKey token=new MiaoshaUserKey(TOKEN_EXPIRE,"tk");
	//对象缓存一般没有有效期,永久有效
	public static MiaoshaUserKey getById=new MiaoshaUserKey(0,"id");
	}

具体实现类的具体使用场景:

	/**
	 *避免key被不同类的数据覆盖 
	 *使用Prefix前缀-->不同类别的缓存,用户、部门、
	 */
	@RequestMapping("/redis/set")
	@ResponseBody
	public Result<Boolean> redisSet() {//0代表成功		
		User user=new User(1,"1111");
		boolean f=redisService.set(UserKey.getById,""+1,user);
		return Result.success(true);
	}
	@RequestMapping("/redis/getbyid")
	@ResponseBody
	public Result<User> redisGetById() {//0代表成功		
		User res=redisService.get(UserKey.getById,""+1,User.class);
		//redisService.get("key1",String.class);
		//System.out.println("res:"+userService.tx());
		return Result.success(res);
	}

完善后的get和set缓存的Key值的方法:

	public <T> T get(KeyPrefix prefix,String key,Class<T> data){
		Jedis jedis=null;
		//在JedisPool里面取得Jedis
		try {
			jedis=jedisPool.getResource();
			//生成真正的key  className+":"+prefix;  BasePrefix:id1
			String realKey=prefix.getPrefix()+key;
			//System.out.println("jedis:"+jedis);
			String sval=jedis.get(realKey);
			//将String转换为Bean入后传出
			T t=stringToBean(sval,data);
			return t;
		}finally {
			returnToPool(jedis);
		}
	}
	/**
	 * 设置单个、多个对象
	 */						
	 //MiaoshaUserKey.token, token, user
	public <T> boolean set(KeyPrefix prefix,String key,T value){		
		Jedis jedis=null;
		try {//在JedisPool里面取得Jedis
			jedis=jedisPool.getResource();
			String realKey=prefix.getPrefix()+key;		
			String s=beanToString(value);		
			if(s==null||s.length()<=0) {
				return false;
			}
			int seconds=prefix.expireSeconds();
			if(seconds<=0) {//有效期:代表不过期,这样才去设置
				jedis.set(realKey, s);
			}else {//没有设置过期时间,即没有设置有效期,那么自己设置。
				jedis.setex(realKey, seconds,s);				
			}
			return true;
		}finally {
			returnToPool(jedis);			
		}
	}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员小台

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值