SpringBoot秒殺系統實戰07-通用緩存Key的設計與封裝

爲什麼要這個通用緩存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);			
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章