您在此之前可能已經緩存過模型數據,但是我將向您展示一個使用動態記錄模型的更精細的Laravel 模型緩存技術,這是我一開始在RailsCasts 學習到的技術。
使用模型的唯一快取鍵,您可以快取模型(或關聯模型)更新時自動更新(以及快取失效)的模型上的屬性和關聯,一個好處是存取快取的資料比在控制器中快取的資料更具可重複性,因為它在模型上而不是在單一控制器方法中。
這是這個技術的要點:
假設你有很多個Comment 的Article 模型,給定下面的Laravel blade 模板,你就可以像下面這樣訪問/article/:id 路由時得到評論的數量:
<h3>$article->comments->count() {{ str_plural('Comment', $article->comments->count())</h3>
您可以在控制器中快取評論的計數,但是當您有多個需要快取的一次性查詢和資料時,控制器會變得非常臃腫難看。使用控制器,存取快取的資料也不是很方便。
我們可以建立一個模板,它僅在文章更新時存取資料庫,並且存取該模型的所有程式碼都可以取得快取值:
<h3>$article->cached_comments_count {{ str_plural('Comment', $article->cached_comments_count)</h3>
透過使用模型存取器,我們可以快取基於最後一次文章更新的評論計數值。
因此,在評論新增或刪除時我們該怎麼更新文章的 updated_at 欄位值呢?
先進入 touch 方法看看。
模型的觸發
可以透過使用模型的touch() 方法來更新文章的updated_at 欄位值:
$ php artisan tinker
>>> $article = \App\Article::first(); => App\Article {#746 id: 1, title: "Hello World", body: "The Body", created_at: "2018-01-11 05:16:51", updated_at: "2018-01-11 05:51:07", } >>> $article->updated_at->timestamp => 1515649867 >>> $article->touch(); => true >>> $article->updated_at->timestamp => 1515650910
我們可以用更新的timestamp 值讓快取失效。不過在新增或刪除一個註解時,我們要怎麼觸發修改文章的 updated_at 欄位呢?
剛好 Eloquent 模型中有一個屬性就叫 $touches 。以下是我們的評論模型的大概樣子:
<?php namespace App; use App\Article; use Illuminate\Database\Eloquent\Model; class Comment extends Model { protected $guarded = []; protected $touches = ['article']; public function article() { return $this->belongsTo(Article::class); } }
這裡的 $touches 屬性是個數組,包含了在評論的創建、保存和刪除時會引起 “觸發” 的關聯信息。
快取的屬性
我們先回到 $article->cached_comments_count 存取器。此方法的實作可能像 App\Article 模型中的樣子:
public function getCachedCommentsCountAttribute() { return Cache::remember($this->cacheKey() . ':comments_count', 15, function () { return $this->comments->count(); }); }
我們使用唯一鍵值的 cacheKey() 方法快取模型 15 分鐘,然後簡單地在閉包方法中傳回評論計數值。
注意,我們也用到了 Cache::rememberForever() 方法,靠著快取機制的垃圾回收策略以刪除過期的鍵值。我設定了一個定時器,以便在每隔 15 分鐘的快取刷新間隔裡,快取可在該時間的多數範圍內有最高的命中率。
cacheKey() 方法要使用到模型的唯一鍵值,並且在模型更新時對應快取失效。以下是我的cacheKey 實作程式碼:
public function cacheKey() { return sprintf( "%s/%s-%s", $this->getTable(), $this->getKey(), $this->updated_at->timestamp ); }
模型的cacheKey() 方法範例輸出結果可能會回傳下面的字串資訊:
articles/1-1515650910
這個鍵值是由表名、模型id 值及當前updated_at 的timestamp 值組成。一旦我們觸發這個模型,timestamp 值就會更新,並且我們的模型快取就會相應地失效。
以下是 Article 模型的完整程式碼:
<?php namespace App; use App\Comment; use Illuminate\Support\Facades\Cache; use Illuminate\Database\Eloquent\Model; class Article extends Model { public function cacheKey() { return sprintf( "%s/%s-%s", $this->getTable(), $this->getKey(), $this->updated_at->timestamp ); } public function comments() { return $this->hasMany(Comment::class); } public function getCachedCommentsCountAttribute() { return Cache::remember($this->cacheKey() . ':comments_count', 15, function () { return $this->comments->count(); }); } }
然後是關聯的 Comment 模型:
<?php namespace App; use App\Article; use Illuminate\Database\Eloquent\Model; class Comment extends Model { protected $guarded = []; protected $touches = ['article']; public function article() { return $this->belongsTo(Article::class); } }
接下來要做什麼?
我已經向你展示瞭如何快取一個簡單的評論計數,但是如何快取所有的評論呢?
public function getCachedCommentsAttribute() { return Cache::remember($this->cacheKey() . ':comments', 15, function () { return $this->comments; }); }
你也可以選擇將評論轉換為數組替代序列化模型,只允許在前端對資料進行簡單的數組存取:
public function getCachedCommentsAttribute() { return Cache::remember($this->cacheKey() . ':comments', 15, function () { return $this->comments->toArray(); }); }
最後, 我在Article 模型中定義了cacheKey () 方法,但你可能想要透過一個名為ProvidesModelCacheKey 的trait 來定義這個方法以便你可以在複合模型中使用或在一個基礎模型中定義所有模型擴充的方法。你甚至可能想要為實作 cacheKey() 方法的模型使用使用契約 (介面)。
以上是如何在 Laravel 中在 Model 層進行資料快取?的詳細內容。更多資訊請關注PHP中文網其他相關文章!