Dưới đây là hướng dẫn chi tiết cách sử dụng Memcached trong Laravel 12 để cache kết quả truy vấn DB nặng — giúp giảm tải MySQL và tăng tốc độ phản hồi:
Giả sử bạn có truy vấn phức tạp như sau:
$posts = DB::table('posts')
->where('status', 'published')
->orderBy('views', 'desc')
->take(100)
->get();
Bạn muốn cache kết quả truy vấn này trong Memcached trong 10 phút.
.env
CACHE_DRIVER=memcached
php -m
có memcached
:php -m | grep memcached
Nếu chưa, cài đặt bằng:
sudo apt install php-memcached
sudo systemctl restart php8.x-fpm
Cache::remember()
để cache truy vấn DB$data = Cache::remember('cache_key', $seconds, function () {
return DB::table('...')->get();
});
use IlluminateSupportFacadesCache;
use IlluminateSupportFacadesDB;
$posts = Cache::remember('top_100_published_posts', 600, function () {
return DB::table('posts')
->where('status', 'published')
->orderBy('views', 'desc')
->limit(100)
->get();
});
✅ Kết quả sẽ được cache trong Memcached trong 600 giây = 10 phút. Sau thời gian đó, truy vấn sẽ chạy lại và nạp cache mới.
$categoryId = 5;
$posts = Cache::remember("top_posts_category_{$categoryId}", 600, function () use ($categoryId) {
return DB::table('posts')
->where('category_id', $categoryId)
->where('status', 'published')
->orderBy('views', 'desc')
->limit(100)
->get();
});
Cache::rememberForever('about_us_page', function () {
return DB::table('pages')->where('slug', 'about-us')->first();
});
Cache::forget('top_100_published_posts');
Sử dụng:
echo "stats items" | nc localhost 11211
Tách logic ra để dễ tái sử dụng:
class PostRepository
{
public function getTopPublished($limit = 100)
{
return Cache::remember("top_published_posts_{$limit}", 600, function () use ($limit) {
return DB::table('posts')
->where('status', 'published')
->orderBy('views', 'desc')
->limit($limit)
->get();
});
}
}
Tác vụ | Cache tốt không? |
---|---|
Truy vấn SELECT nặng | ✅ Nên cache |
Kết quả phân trang | ✅ Có thể cache |
Truy vấn có tham số | ✅ Tạo key động |
INSERT/UPDATE/DELETE | ❌ Không cache |
Cache::remember()
với Eloquent Query BuilderEloquent cũng giống như Query Builder, bạn có thể cache như sau:
use IlluminateSupportFacadesCache;
use AppModelsPost;
$posts = Cache::remember('top_posts', 600, function () {
return Post::where('status', 'published')
->orderByDesc('views')
->limit(100)
->get();
});
remember
với tham số động và query phức tạpVí dụ: cache top bài viết theo danh mục, trạng thái, user…
$categoryId = 5;
$status = 'published';
$userId = 3;
$cacheKey = "top_posts_cat_{$categoryId}_status_{$status}_user_{$userId}";
$posts = Cache::remember($cacheKey, 600, function () use ($categoryId, $status, $userId) {
return Post::where('category_id', $categoryId)
->where('status', $status)
->where('user_id', $userId)
->orderByDesc('views')
->limit(100)
->get();
});
❗ Memcached mặc định không hỗ trợ tag trong Laravel. Nếu bạn cần xóa nhiều key theo nhóm (ví dụ: tất cả cache liên quan đến
posts
), bạn nên chuyển sang Redis.
Trong .env
:
CACHE_DRIVER=redis
Sau đó, bạn có thể làm như sau:
Cache::tags(['posts', 'top'])->remember('top_posts', 600, function () {
return Post::orderByDesc('views')->take(100)->get();
});
posts
:Cache::tags(['posts'])->flush();
$page = request()->get('page', 1);
$key = "top_posts_page_{$page}";
$posts = Cache::remember($key, 600, function () {
return Post::where('status', 'published')->paginate(10);
});
✅ Bạn nên đặt thời gian cache ngắn hơn khi dữ liệu hay thay đổi (ví dụ 60s – 300s).
Bạn có thể cache toàn bộ response HTML hoặc dữ liệu JSON từ controller:
$response = Cache::remember('homepage_view', 600, function () {
return view('homepage', [
'posts' => Post::latest()->take(10)->get(),
'news' => News::latest()->take(5)->get(),
])->render();
});
return response($response);
// PostService.php
public function getCachedPopular($categoryId = null)
{
$key = 'popular_posts_' . ($categoryId ?: 'all');
return Cache::remember($key, 600, function () use ($categoryId) {
$query = Post::where('status', 'published');
if ($categoryId) {
$query->where('category_id', $categoryId);
}
return $query->orderBy('views', 'desc')->take(50)->get();
});
}
Tình huống cần cache | Nên dùng gì? |
---|---|
Truy vấn SELECT phức tạp | ✅ Cache bằng remember |
Truy vấn có nhiều biến động | ✅ Cache ngắn (30s–120s) |
Xóa cache theo nhóm (tag) | ❌ Memcached không hỗ trợ tag |
Cache dữ liệu ít thay đổi (about us) | ✅ rememberForever() |
Cache toàn bộ view/json | ✅ render() rồi cache |
Bạn có thể dùng Eloquent Event để tự động xóa cache khi Model bị thay đổi, ví dụ như cập nhật bài viết hoặc xóa bài viết.
Post
thay đổi// AppModelsPost.php
protected static function booted()
{
static::saved(function ($post) {
Cache::forget('top_posts');
});
static::deleted(function ($post) {
Cache::forget('top_posts');
});
}
✅ Khi bạn
update
,create
, hoặcdelete
bài viết, cachetop_posts
sẽ tự bị xóa, tránh dùng dữ liệu cũ.
Thay vì chỉ cache kết quả query, bạn có thể cache cả response HTML hoặc JSON API, để Laravel không phải chạy Controller nữa.
composer require spatie/laravel-responsecache
// AppHttpKernel.php
protected $middlewareGroups = [
'web' => [
...
SpatieResponseCacheMiddlewaresCacheResponse::class,
],
];
.env
:RESPONSECACHE_ENABLED=true
use SpatieResponseCacheFacadesResponseCache;
Route::get('/homepage', 'HomeController@index')->middleware('cache.response');
✅ Mỗi lần truy cập route
/homepage
, toàn bộ response (HTML hoặc JSON) được cache lại (thường là 60 phút).
Route::get('/top-posts', function () {
return Cache::remember('api_top_posts', 600, function () {
return Post::where('status', 'published')->orderByDesc('views')->limit(50)->get();
});
});
Trường hợp | Key mẫu |
---|---|
Truy vấn theo danh mục | posts_cat_{$catId}_page_{$page} |
Kết quả JSON API | api_response_homepage |
Cache theo user | user_{$userId}_dashboard_data |
➕ Nhờ vậy, bạn dễ xóa cache khi cần:
Cache::forget("user_{$userId}_dashboard_data");
Ví dụ bạn xử lý query rất nặng, bạn có thể:
dispatch(new GenerateTopPostsCache());
class GenerateTopPostsCache implements ShouldQueue {
public function handle() {
$data = Post::where('status', 'published')->orderByDesc('views')->take(100)->get();
Cache::put('top_posts', $data, now()->addMinutes(30));
}
}
Laravel hỗ trợ lệnh kiểm tra cache:
php artisan tinker
>>> Cache::get('top_posts');
Loại dữ liệu | Cache như nào |
---|---|
Truy vấn SELECT nặng | Cache::remember() |
Kết quả JSON API | Cache::remember() hoặc middleware response |
Dữ liệu view toàn trang | view()->render() + cache |
Dữ liệu thường xuyên cập nhật | cache ngắn (30–300s) |
Cần xoá theo nhóm | dùng Redis + tag |
Auto clear khi DB thay đổi | dùng Model::saved() / deleted() |
Cache lâu dài (ít khi thay đổi) | Cache::rememberForever() |