Hướng dẫn Laravel Model Caching
Có thể trước đây bạn đã từng cache một số data model trên controller, nhưng giờ tôi sẽ chỉ cho bạn một kỹ thuật cache Laravel model sử dụng model Active Record phức tạp hơn một chút. Đây là kỹ thuật tôi học được từ RailsCasts.
Bằng việc sử dụng cache key riêng biệt lên model, bạn có thể cache các properties và associations tự động update lên model của mình (và cache hết hiệu lực) khi model (hoặc model liên quan) được update. Một lợi ích khác đó là việc truy cập vào data được cache trên model tiện lợi hơn việc cache data trên controller.
Dưới đây là phần lý giải của kỹ thuật này:
Xem như bạn có một model Article
mà có chứa nhiều model Comment
. Khi được cho template Laravel blade như dưới đây, bạn có thể nhận về số comment như thế trên route /article/:id
:
<h3>$article->comments->count() {{ str_plural('Comment', $article->comments->count())</h3>
Bạn có thể cache phần comment count trong controller, nhưng controller có thể trở nên khá tệ khi bạn có nhiều query và data cần phải cache. Việc sử dụng controller, truy cập vào data được cache cũng không được thuận tiện cho lắm.
Chúng ta có thể xây dựng một template mà chỉ thực hiện việc truy cập database khi article được update, và bất kì code nào có access vào model đều có thể lấy giá trị được cache:
<h3>$article->cached_comments_count {{ str_plural('Comment', $article->cached_comments_count)</h3>
Chúng ta sẽ cache lượng comment count dựa theo lần cuối mà article được update.
Vậy bằng cách nào mà chúng ta update cột updated_at
của article khi một comment mới được thêm vào hoặc xóa đi?
Sử dụng phương thức touch.
>>> Xem thêm: Laravel, bạn đã viết đúng?
Touching Models
Việc sử dụng method touch()
của model, chúng ta có thể update cột updated_at
của article:
$ 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
Chúng ta có thể sử dụng timestamp đã update để invalidate cache, nhưng làm sao để đụng tới trường updated_at
của article khi chúng ta thêm hoặc bỏ đi comment?
Việc này cũng xảy ra tương tự khi model Eloquent có một thành phần gọi là $touches
. Comment model của chúng tôi được diễn giải như sau:
<?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
là một mảng chứa một liên kết sẽ được “touch” khi một comment được tạo ra, lưu về hoặc xóa đi.
Thuộc tính Cached (cached attribute)
Quay lại phần $article->cached_comments_count
. Phần thực hiện có thể trông như thế này trên model App\Article
:
public function getCachedCommentsCountAttribute() { return Cache::remember($this->cacheKey() . ':comments_count', 15, function () { return $this->comments->count(); }); }
Chúng ta đang cache model trong khoảng 15 phút bằng method cacheKey()
riêng biệt và quay lại phần đếm comment trong phần closure.
Lưu ý rằng chúng ta có thể sử dụng method Cache::rememberForever()
và dựa vào thùng rác tạm trên bộ nhớ đệm để loại bỏ key cũ. Tôi đã cài đếm giờ để cache sẽ được truy cập mọi lúc, với một cache mới mỗi 15 phút.
method cacheKey()
cần phải làm trên model riêng biệt, và vô hiệu cache khi model được update. Dưới đây là phần ứng dụng cacheKey
của tôi:
public function cacheKey() { return sprintf( "%s/%s-%s", $this->getTable(), $this->getKey(), $this->updated_at->timestamp ); }
Một ouput mẫu của method cacheKey()
có thể cho ra kết quả như sau:
articles/1-1515650910
Mấu chốt là tên bảng, model id, và updated_at
. Một khi đụng tới model, timestamp sẽ được update, và cache model sẽ được vô hiệu hóa ngay.
Dưới đây là model Article
đầy đủ:
<?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(); }); } }
Và model Comment
liên quan:
<?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); } }
Tiếp đến là gì?
Tôi đã chỉ ra cách cache một hàm đếm comment đơn giản, nhưng làm thế nào để cache tất cả comment?
public function getCachedCommentsAttribute() { return Cache::remember($this->cacheKey() . ':comments', 15, function () { return $this->comments; }); }
Bạn cũng có thể chọn chuyển đổi comment thành array:
public function getCachedCommentsAttribute() { return Cache::remember($this->cacheKey() . ':comments', 15, function () { return $this->comments->toArray(); }); }
Cuối cùng, tôi define method cacheKey()
vào Article
model, nhưng bạn nên define method này qua ProvidesModelCacheKey
để có thể dùng trên nhiều model hoặc define method trên model gốc mà tất cả các model khác kế thừa. Thậm chí bạn còn muốn dùng contract (interface) cho các model để áp dụng method cacheKey()
.
Tham khảo thêm các vị trí tuyển dụng lập trình Laravel lương cao cho bạn.
TopDev via Laravel News
- M Mới ra trường không kinh nghiệm, sao làm BA?
- C Chuyển đổi SA key sang Workload Identity
- U Use Case Diagram và 5 sai lầm thường gặp
- K Kinh nghiệm xử lý câu lệnh điều kiện trong JavaScript
- D Dart là gì? Ứng dụng của ngôn ngữ lập trình Dart
- C Chuẩn Hóa CV, Nhận Ngay Phím Chất
- S So sánh MySQL và MongoDB: Nên chọn CSDL nào?
- D Dân BA có cần phải rành về kỹ thuật???
- C CSS Selector là gì? Cách sử dụng các loại CSS Selector phổ biến
- P Phân biệt Sketch, Wireframe, Mockup, và Prototype?