說起緩存,相信大家都不陌生,下面我們先看這張圖
上圖是一個最簡單的應用系統業務流轉模型,當一個客戶端連接到server時,需要做數據訪問,在server中會判斷是否已經在緩存中,如果在則直接在緩存中拿出數據返回,由於緩存是在內存中的(比如redis,mongo,sping-cache等),不用大批量的跟數據庫進行交互,避免了大量io操作,大大提高效率。
下面,我們來考慮一個問題,可以設想下如下場景:
當應用啓動起來的瞬間,n(非常大)個用戶訪問儘量,都訪問同一波熱點數據,這種情況很可能導致,數據庫承受不了大量io導致數據庫瞬間癱瘓。
爲了避免這個情況,出現了緩存預熱這個解決方案,當然實現方式有很多中,核心思想都是在應用啓動的過程中將數據寫進緩存系統中,從而使使用過程中可以直接提高系統的緩存命中率(當然不可能將所有的數據全部寫進緩存中),減少數據庫jdbc操作。
下面主要來說說使用@PostConstruct來實現我們的緩存預熱。
從Java EE5規範開始,Servlet中增加了兩個影響Servlet生命週期的註解,@PostConstruct和@PreDestroy,這兩個註解被用來修飾一個非靜態的void()方法。
在spring的bean生命週期中,被@PostConstruct的方法會在實例初始化完成後執行,做一個生命週期的回掉。
redis連接篇:https://blog.csdn.net/baomw/article/details/89186501
我們先假設,數據庫中某張表的前4000個使熱點數據,然後我們在容器啓動的時候將這4000條數據緩存到redis中去。
dao類代碼如下:
@Select("select id,tel from tel order by id asc limit 4000")
public List<HashMap> getList();
service類測試代碼如下:
@Autowired
private TelDao telDao;
@Autowired
private StringRedisTemplate redisTemplate;
@PostConstruct
public void init(){
List<HashMap> list = telDao.getList();
for (HashMap map:list){
//操作string
redisTemplate.opsForValue().set(map.get("id").toString(),map.get("tel").toString());
System.out.println(map.get("id").toString()+"----"+redisTemplate.opsForValue().get(map.get("id").toString()));
}
}
在spring容器啓動的時候初始化redis緩存,如下圖可以看到緩存數據都被加載到redis中去了。
我們連接redis-cli,keys *發現數據確實都被緩存到redis中去了。
如此一個簡單的緩存預熱已經完成了。