爲什麼要這個通用緩存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);
}
}