最近看到了幾種加緩存的方法掰曾,整理對比一下雹顺。
拿一個case來說,我們要去數(shù)據(jù)庫取一條用戶記錄稚矿,迫于性能,還要加一層緩存佑稠。我們針對這個問題看看幾種使用姿勢的對比。
Laravel 中 Facades 做法
$person = Cache::remember("person.{$id}", 5, function () use ($id) {
return PersonDao::find($id);
});
Spring Cache 的做法
@Cache(key = "person#id", ttl = 5)
public Person getPerson(Integer id) {
return PersonDao.find(id);
}
Person person = repository.getPerson();
備注:
- PersonDao.find 表示從DB里去拿數(shù)據(jù)
這兩種方法看起來都很簡單旗芬,除了必要的語法格式舌胶,你需要寫的代碼就是:
- cache 函數(shù)或標(biāo)記,表明需要緩存
- key 不解釋
- ttl 不解釋
- func… 回源數(shù)據(jù)
基本上可以說是要啥寫啥了疮丛,不啰嗦幔嫂。
其實(shí) Php 和 Java 的語法很接近,兩種方法在兩種語言里都適用誊薄。不過 Php 需要第三方的注解支持履恩;Java 需要 8 以上來支持 lambda。
簡單的東西一定面臨擴(kuò)展性的問題呢蔫,我們來看一看他們的可能性似袁。
如果我們要更換緩存驅(qū)動怎么辦?
Laravel
Cache::store('redis')->remember(...)
Spring
@Cache(driver = redisCache.class)
依然很簡單咐刨。
有些時候昙衅,在使用 redis 作為緩存的時候,我們會用不同的編碼
Laravel
Cache::store('redis')->encoding('json')->remember(...)
Spring
@Cache(encoding = JsonEncoding.class)
方法其實(shí)是相似的定鸟,一般的而涉,Lavavel 利用自己習(xí)慣的鏈?zhǔn)讲僮骱?Php 的不定參數(shù),可以讓你隨時傳入自己個性化的需求联予。Spring 也利用 Annotation 來實(shí)現(xiàn)類似的效果啼县。
更多的,Laravel 和 Spring Boot 都遵循了約定優(yōu)于配置的原則沸久,使得在大多數(shù)情況下季眷,你都不需要傳這些,只需要使用全局的默認(rèn)配置就能滿足需求卷胯。也就是上面的最方便的辦法子刮。
簡單的方法介紹完了,我們來聊聊 Go 里的做法
剛剛接手一個 Go 項(xiàng)目窑睁,里面看到是這樣處理緩存的:
proxy := Proxy{
Prefered: RedisAdapter{
RedisClient
},
Backup: DaoAdapter{
PersonDao
}
}
person := proxy.Get('xxx').(Person)
是不是一下看懵逼了挺峡,我也是,這還是簡化的版本担钮。真正實(shí)現(xiàn)一個這樣的功能橱赠,大約新增了三個實(shí)現(xiàn)了數(shù)個空接口新類和幾個方法。
更蛋疼的箫津,這三個類都是類型相關(guān)的狭姨,換句話說宰啦,list/detail 兩種功能各自都需要3個類,換個 model 也不能復(fù)用饼拍。更悲催的赡模,因?yàn)?IDE 對 Go 的 interface 分析都不太好,當(dāng)你閱讀別人的代碼的時候惕耕,你完全不知道哪里是哪里。
所以诫肠,這里想嘗試一下司澎,能否在 Go 里使用上面的簡單方法處理緩存。
id := 9
person := remember("key", 30 * time.Second, func() interface{} {
return PersonDao.find(id)
}).(*Person)
// 或者更 Go 一點(diǎn)
var person Person
remember(&person, "key", 30 * time.Second, func(iface interface{}) {
*iface.(*Person) = *PersonDao.find(id)
})
比較煩的是栋豫,Go 不支持泛型挤安,定義函數(shù)的時候要盡可能少依賴類型。常用的辦法是把類型傳入丧鸯。
前者看起來簡單蛤铜,但有個很要命的地方,你需要很嚴(yán)格的把 Person 類進(jìn)行序列化丛肢。否則從 cache 里取出來后類型可能會丟围肥,導(dǎo)致斷言失敗。
那么蜂怎,第二種辦法可以嗎穆刻?或者說,在 Go 里能不能通過簡單標(biāo)記的辦法來實(shí)現(xiàn)多態(tài)杠步?
我只能說氢伟,不好弄。
Spring 里很多注解效果幽歼,都是靠動態(tài)代理實(shí)現(xiàn)的(相當(dāng)于 Php 里閹割版的 __call )朵锣。但遺憾的是,Go 目前不能支持這一特性甸私。如果要硬上的話诚些,也可以,搞出來可能跟我接的代碼挺像的皇型。