自增瀏覽數
最近一個專案用到自增瀏覽數,首先考慮到的就是在資料表中加個 view_count
欄位,並在每次訪問時 increment
自增。日復一日,每次訪問執行 update
,對效能是十分不利的。
看了 9.4. 使用者最後登入時間《L02 Laravel 教程 - Web 開發實戰進階 ( Laravel 5... ,就使用 Redis + 資料庫 實現了類似的功能。
資料庫欄位
首先需要在資料表中加入一個 view_count
欄位:
$table->unsignedInteger('view_count')->default(0);
增加 ViewCountsHelper Trait
廢話不多說,直接上程式碼,都有完整的註釋。思路來自 https://github.com/summerblue/larabbs/tree... 。
<?php
namespace App\Models\Traits;
use Redis;
use Carbon\Carbon;
trait ViewCountsHelper {
// 快取相關
protected $hash_prefix = 'topic_view_counts_';
protected $field_prefix = 'topic_';
public function viewCountIncrement()
{
// 獲取今日 Redis 雜湊表名稱,如:topic_view_counts_2017-10-21
$hash = $this->getHashFromDateString(Carbon::now()->toDateString());
// 欄位名稱,如:topic_1
$field = $this->getHashField();
// 當前閱讀數,如果存在就自增,否則就為 1
$count = Redis::hGet($hash, $field);
if ($count) {
$count++;
} else {
$count = 1;
}
// 資料寫入 Redis ,欄位已存在會被更新
Redis::hSet($hash, $field, $count);
}
public function syncTopicViewCounts()
{
// 獲取昨日的雜湊表名稱,如:topic_view_counts_2017-10-21
$hash = $this->getHashFromDateString(Carbon::now()->toDateString());
// 從 Redis 中獲取所有雜湊表裡的資料
$counts = Redis::hGetAll($hash);
// 如果沒有任何資料直接 return
if (count($counts) === 0) {
return;
}
// 遍歷,並同步到資料庫中
foreach ($counts as $topic_id => $view_count) {
// 會將 `topic_1` 轉換為 1
$topic_id = str_replace($this->field_prefix, '', $topic_id);
// 只有當話題存在時才更新到資料庫中
if ($topic = $this->find($topic_id)) {
$topic->view_count = $this->attribute['view_count'] + $view_count;
$topic->save();
}
}
// 以資料庫為中心的儲存,既已同步,即可刪除
Redis::del($hash);
}
public function getViewCountAttribute($value)
{
// 獲取今日對應的雜湊表名稱
$hash = $this->getHashFromDateString(Carbon::now()->toDateString());
// 欄位名稱,如:topic_1
$field = $this->getHashField();
// 三元運算子,優先選擇 Redis 的資料,否則使用資料庫中
$count = Redis::hGet($hash, $field) ? : $value;
// 如果存在的話,返回 資料庫中的閱讀數 加上 Redis 中的閱讀數
if ($count) {
return $this->attribute['view_count'] + $count;
} else {
// 否則返回 0
return 0;
}
}
public function getHashFromDateString($date)
{
// Redis 雜湊表的命名,如:topic_view_counts_2017-10-21
return $this->hash_prefix . $date;
}
public function getHashField()
{
// 欄位名稱,如:topic_1
return $this->field_prefix . $this->id;
}
}
然後在需要此功能的模型中 use Traits\ViewCountsHelper
即可。
每天將瀏覽量同步到資料庫
app/Console/Commands/SyncTopicViewCounts.php
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Models\Topic;
class SyncTopicViewCounts extends Command
{
protected $signature = 'topic:sync-topic-view-counts';
protected $description = '將話題 view_count 從 Redis 同步到資料庫中';
/**
* Execute the console command.
*
* @return mixed
*/
public function handle(Topic $topic)
{
$topic->syncTopicViewCounts();
$this->info("同步成功!");
}
}
app/Console/Kernel.php
protected function schedule(Schedule $schedule)
{
// ...
$schedule->command('topic:sync-topic-view-counts')->dailyAt('00:00');
}
使用
<?php
namespace App\Http\Controllers;
use App\Models\Topic;
use Illuminate\Http\Request;
class TopicsController extends Controller
{
public function show(Topic $topic)
{
$topic->viewCountIncrement(); // 自增瀏覽數
dd($topic->view_count); // 獲取瀏覽數
}
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結