(一)什麼是redis
1.redis -cache 緩存:是一個軟件(service層) 高能併發讀取
基於內存亦可持久化的日誌型、Key-Value數據庫,每秒處理請求幾十萬(常用來做數據緩存)
2.應用:網易、阿里、美團-----spring+redis
(二)爲什麼用redis
當十幾萬/幾十萬/秒的請求量(QPS:每秒訪問次數)時,使用redis可以提高性能。
性能高的原因?redis緩存中的內容存到內存
(三)如何使用redis
1.先在service層寫如下代碼
spring集成redisTemplate(jvm外置HashMap)
public skuProjo findById(string key){
//1、判斷緩存中是否存在(redis-cache)
Object value = redisTemplate.opsForValue().get(key); //網絡請求--redis-server --內存中讀取數據
if(value != null) {
System.out.println("從緩存中讀取了值");
return (SkuProjo) value;
}
//2.不存在執行數據查詢
System.out.println("數據查詢方法執行中");
value = skuDao.find(key); //正式的業務代碼
//3.同步存儲value到緩存中
redisTemplate.opsForVale().set(key,value);
return (SkuProjo) value;
}
優點:性能高
缺點:
代碼業務功能和基礎組件功能混合
代碼出現複製粘貼的情況,沒有合理的抽出公共包
臃腫的代碼,多個功能模板寫的邏輯都是類似的
2.代碼升級
緩存+註解=高效便捷
service層:
@NeteaseEduCache(key = "#id") //緩存註解
public SkuProjo findById(string id) {
//查詢數據庫
SkuProjo skuProjo = skuDao.find(id); //正式的業務代碼
return skuProjo;
}
CacheAespet
public class CacheAespect {
@Autowired
RedisTemplate redisTemplate;
@Around("@annotation(com.netease.kaola.sku.common.cache.NeteaseEduCache)")
public Object queryCache(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("方法執行之前");
String keyEL = ""; //動態變化 TODO 1.取出當前運行的這個方法上面註解中的key內容
MethodSignature signature = (MethodSingnature) joinPoint.getSingnature();
Method method = joinPoint.getTarget().getClass().getMethod(singnature.getName(), singture.getMethod(), getParamterTypes());
NeteaseEduCache cacheAnnotation = method.getAnnotation(NeteaseEduCache.class);
keyEL = cacheAnnotation.key();
//1.創建解析器
ExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression(keyEL);
//2.設置解析上下文(有哪些佔位符,以及每種佔位符的值)
EvaluationContent content = new StandardEvaluationContent(); //參數
//真實參數名(運行時獲取參數名:arg() arg1 arg2)
Object[] args = jointPoint.getArgs();
DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
String[] parameterNames = discoverer.getParameterNames(method);
for (int i =0; i<parameterNames.length; i++) {
contetxt.setVariable(parameterNames[i], args[i]); //TODO 2.變量的值來自方法參數
}
//3.解析
String key = expression.getValue(content).toString();
//1、判斷緩存中是否存在
Object value = redisTemplate.opsForValue().get(key); //網絡請求--redis-server --內存中讀取數據
if(value != null) {
System.out.println("從緩存中讀取了值");
return (SkuProjo) value;
}
//2.不存在執行數據查詢
Object result = joinPoint.proceed(); // 觸發目標方法執行
System.out.println("數據查詢方法執行中");
//3.同步存儲value到緩存中
redisTemplate.opsForVale().set(key,result);
return result;
}
}
概念拓展
1.註解
和普通代碼註釋的不同?
Java註解又稱Java標註,是Java語言5.0版本開始支持加入源代碼的特殊語法元數據。
普通的註釋在編譯後的class文件中不存在的,
而註解附加的信息則是根據需要可以保存到class文件中,甚至運行期加載的class對象中。
簡單來說:註解就是附件信息、貼標籤。
註解分爲:類上面的註解、屬性上面的註解、方法上面的註解
2.spring EL表達式
service層
public class SkuQueryService {
@Autowired
SkuDao skuDao;
@Autowired
private RedisTemplate redisTemplate;
@Value("${jdbc.username}") //替換配置信息
String jdbcUsername;
@NeteaseEduCache(key = "#skuId") //緩存註解
public SkuProjo findById(string skuId) {//id都可能不同
System.out.println("數據庫查詢的主體方法被觸發執行");
SkuProjo value= skuDao.find(skuId); //正式的業務代碼
return value;
}
}
單元測試
public class SpringELTests {
@Test
public void test() {
//java佔位符
String template = "%s : 測試中";
String result = String.format(template, "我是Lenka");
System.out.println(result);
}
@Test
public void SPELTest() thorws IOException Exception {
String ELdemo = "'hellp' + #userId"; //EL表達式(可以簡單理解爲動態的佔位符)
//1.創建解析器
ExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression(ELdemo);
//2.設置解析上下文(有哪些佔位符,以及每種佔位符的值)
EvaluationContent content = new StandardEvaluationContent(); //參數
context.setVariable(name:"userId",value: "lenka");
//3.解析
String result= expression.getValue(content).toString();
System.out.println(result);
}
}
3.spring AOP
1.圖示:
4.數據庫性能表
TPS:Transaction Per Second, 數據庫每秒執行的事務數,以commit爲準。
QPS: Query Per Second, 數據庫每秒執行的SQL數(含 insert、select、update、delete等)