怎樣快速的使用緩存 Cache

最近看到了幾種加緩存的方法,整理對(duì)比一下。

拿一個(gè)case來說,我們要去數(shù)據(jù)庫取一條用戶記錄,迫于性能,還要加一層緩存。我們針對(duì)這個(gè)問題看看幾種使用姿勢(shì)的對(duì)比。

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ū)動(dòng)怎么辦?

Laravel

Cache::store('redis')->remember(...)

Spring

@Cache(driver = redisCache.class)

依然很簡單。

有些時(shí)候,在使用 redis 作為緩存的時(shí)候,我們會(huì)用不同的編碼

Laravel

Cache::store('redis')->encoding('json')->remember(...)

Spring

@Cache(encoding = JsonEncoding.class)

方法其實(shí)是相似的,一般的,Lavavel 利用自己習(xí)慣的鏈?zhǔn)讲僮骱?Php 的不定參數(shù),可以讓你隨時(shí)傳入自己個(gè)性化的需求。Spring 也利用 Annotation 來實(shí)現(xiàn)類似的效果。

更多的,Laravel 和 Spring Boot 都遵循了約定優(yōu)于配置的原則,使得在大多數(shù)情況下,你都不需要傳這些,只需要使用全局的默認(rèn)配置就能滿足需求。也就是上面的最方便的辦法。

簡單的方法介紹完了,我們來聊聊 Go 里的做法

剛剛接手一個(gè) Go 項(xiàng)目,里面看到是這樣處理緩存的:

proxy := Proxy{
    Prefered: RedisAdapter{
        RedisClient
    },
    Backup: DaoAdapter{
        PersonDao
    }
}
person := proxy.Get('xxx').(Person)

是不是一下看懵逼了,我也是,這還是簡化的版本。真正實(shí)現(xiàn)一個(gè)這樣的功能,大約新增了三個(gè)實(shí)現(xiàn)了數(shù)個(gè)空接口新類和幾個(gè)方法。

更蛋疼的,這三個(gè)類都是類型相關(guān)的,換句話說,list/detail 兩種功能各自都需要3個(gè)類,換個(gè) model 也不能復(fù)用。更悲催的,因?yàn)?IDE 對(duì) Go 的 interface 分析都不太好,當(dāng)你閱讀別人的代碼的時(shí)候,你完全不知道哪里是哪里。

所以,這里想嘗試一下,能否在 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ù)的時(shí)候要盡可能少依賴類型。常用的辦法是把類型傳入。

前者看起來簡單,但有個(gè)很要命的地方,你需要很嚴(yán)格的把 Person 類進(jìn)行序列化。否則從 cache 里取出來后類型可能會(huì)丟,導(dǎo)致斷言失敗。

那么,第二種辦法可以嗎?或者說,在 Go 里能不能通過簡單標(biāo)記的辦法來實(shí)現(xiàn)多態(tài)?

我只能說,不好弄。

Spring 里很多注解效果,都是靠動(dòng)態(tài)代理實(shí)現(xiàn)的(相當(dāng)于 Php 里閹割版的 __call )。但遺憾的是,Go 目前不能支持這一特性。如果要硬上的話,也可以,搞出來可能跟我接的代碼挺像的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容