什麼是緩存穿透和雪蹦?
緩存是為了減輕資料庫的壓力、提升資料的查詢效率。但是按照一般邏輯,資料在緩存中沒有取到就會去資料庫中擷取,如果大量的通路都沒有在緩存中擷取到資料,就有“穿透”的問題,進而帶來緩存雪蹦的問題。
1、大并發環境下,第一次通路緩存,發現緩存中沒有資料,然後所有線程都會去通路資料庫,這樣就造成緩存短暫失效,這就是“緩存穿透”。緩存穿透的危害:導緻大量的請求直接到資料庫,導緻資料庫的承載壓力過大導緻當機。
2、資料庫查詢不到這個資料,在redis中儲存的key所對應的value就為null。那代碼邏輯也會出現穿透。先判斷key是否在緩存中存在,隻要存在key,不論value是否為null,都認為緩存中有 資料,主要有資料就不要再通路資料庫。
解決緩存穿透問題
總結:
1、雙重檢測機制(在鎖的内外都進行緩存查詢,沒有查到在進行資料庫查詢)。
2、不論查詢到的資料是否為null,都将它寫入緩存。
3、避免緩存中的null鍵值撐滿整個記憶體,是以需要給null鍵值設定過期時間。
4、提前分析項目中可能出現并發的資料,提前将這些資料寫入緩存。(在tomcat容器啟動的時候寫入緩存)
5、key的設計,要唯一辨別一條資料,不能被其他資料覆寫。
Object obj = null;
//第一層:解決緩存穿透:通過資料庫沒有的資料進行穿透
if(redisTemplate.hasKey(key)){
//1、讀取緩存
obj = getStringCache(key);
return obj;
}else {
//線程開始排隊
synchronized (this) {
//第二層:解決緩存穿透:通過資料庫沒有的資料進行穿透
if (redisTemplate.hasKey(key)) {
//雙重檢測鎖機制,第二層避免排隊的線程再次查詢資料庫,導緻資料庫的壓力。需要在鎖内部再次查詢緩存
obj = getStringCache(key);
return obj;
} else {
//2、緩存中沒有資料,讀取資料庫資料庫
obj = goodsMapper.queryGoods();
Gson gson = new Gson();
String json = gson.toJson(obj);
if(obj == null){
//如果是空key,避免空key(無效資料)将記憶體消耗完,設定過期時間,定期删除。
//注意:時間也不宜過長,時間過長會導緻無效資料短期内也會撐滿整個記憶體。
addStringCacheEX(key,json,5);
}else {
//3、将資料庫取出的資料寫入緩存,友善第二次從緩存中取資料
addStringCache(key,json);
}
obj = json;
}
}
}
return obj;
}