Laravel Model 優化 - 添加屬性緩存(attribute cache)

問題背景

在咱們的項目中,使用到了大量的attribute函數,來改善咱們在面向業務時的調用方便和代碼層面的優雅,可是一樣也帶來的必定的問題,會產生大量的重複計算和SQL調用,在應用上的性能上形成了一擊。php

咱們來演示一下這個過程,首先定義出一個attribute,這樣咱們能夠方便經過的$user->posts_count,拿到用戶發表的動態總數,像比原來的寫法更加具備語義化,也更優雅了不少。緩存

public function getPostsCountAttribute()
{
        return $this->posts()->count();
}

可是遇到下面這種狀況,就會糟糕了不少,會產生屢次的SQL查詢,來形成服務端響應的緩慢app

if($user->posts_count > 30){
    //處理一
}

if($user->posts_count > 50){
    //處理二
}

if($user->posts_count > 100){
    //處理三
}

if($user->posts_count > 200){
    //處理四
}

像上面這樣的寫法的,咱們可能會形成4次SQL聚合運算,從而影響到咱們的響應速度,固然咱們也能夠嘗試改進代碼規範來解決這個問題,可是仍然不能保證,這個屬性被第二次、三次持續調用,那麼方便、快捷的辦法就是添加一層屬性緩存,將獲取後的值緩存到模型屬性上。框架

屬性緩存(attribute cache)

使用屬性緩存的優點就是簡單、快捷,無需藉助第三方擴展,採用的是面嚮對象語言的原生優點,下面來實現一下:函數

在咱們Larvel框架的項目中,model都是繼承於Eloquent\Model這個基類,咱們從新複寫該基類操做比較繁瑣,因此能夠採用php爲了實現多繼承的trait來實現。post

首先實現一個AttributeCacheHelpertrait性能

<?php

namespace App\Traits;

trait AttributeCacheHelper
{
    private $cachedAttributes = [];

    public function getCachedAttribute(string $key, callable $callable)
    {
        if (!array_key_exists($key, $this->cachedAttributes)) {
            $this->setCachedAttribute($key, call_user_func($callable));
        }

        return $this->cachedAttributes[$key];
    }

    public function setCachedAttribute(string $key, $value)
    {
        return $this->cachedAttributes[$key] = $value;
    }

    public function refresh()
    {
        unset($this->cachedAttributes);

        return parent::refresh();
    }
}

主要是實現了三個函數,get和set用於獲取和設置屬性緩存,refresh重寫了父類的刷新函數,每次刷新後都會清理掉對象緩存。this

而後咱們開始從新修改一下咱們的attribute,來添加對象緩存,首先是須要在Model上使用AttributeCacheHelper這個traitspa

public function getPostsCountAttribute()
{
    $method   = 'postsCount';
    $callable = [$this, $method];
    return $this->getCachedAttribute($method, $callable);
}

public function postsCount()
{
    return $this->posts()->count();
}

修改完成後,咱們再從新應用到場景中,就算執行一萬次,也只會產生1次SQL查詢,極大的提升了查詢效率和響應速度。代碼規範

for($i=0;$i<10000;$i++){
    // 僅產生一次真實查詢,其他所有讀取對象緩存數據
    dump($user->posts_count);
}

最後 happy coding 。

相關文章
相關標籤/搜索