hyperf/docs/zh-hk/cache.md
2023-01-02 23:32:23 +00:00

8.2 KiB
Raw Blame History

Cache

hyperf/cache 提供了基於 Aspect 實現的切面緩存,也提供了實現 Psr\SimpleCache\CacheInterface 的緩存類。

安裝

composer require hyperf/cache

默認配置

配置 默認值 備註
driver Hyperf\Cache\Driver\RedisDriver 緩存驅動,默認為 Redis
packer Hyperf\Utils\Packer\PhpSerializer 打包器
prefix c: 緩存前綴
<?php

return [
    'default' => [
        'driver' => Hyperf\Cache\Driver\RedisDriver::class,
        'packer' => Hyperf\Utils\Packer\PhpSerializerPacker::class,
        'prefix' => 'c:',
    ],
];

使用

Simple Cache 方式

Simple Cache 也就是 PSR-16 規範,本組件適配了該規範,如果您希望使用實現 Psr\SimpleCache\CacheInterface 緩存類,比如要重寫 EasyWeChat 的緩存模塊,可以直接從依賴注入容器中獲取 Psr\SimpleCache\CacheInterface 即可,如下所示:


$cache = $container->get(\Psr\SimpleCache\CacheInterface::class);

註解方式

組件提供 Hyperf\Cache\Annotation\Cacheable 註解,作用於類方法,可以配置對應的緩存前綴、失效時間、監聽器和緩存組。 例如UserService 提供一個 user 方法,可以查詢對應 id 的用户信息。當加上 Hyperf\Cache\Annotation\Cacheable 註解後,會自動生成對應的 Redis 緩存key 值為 user:id ,超時時間為 9000 秒。首次查詢時,會從數據庫中查,後面查詢時,會從緩存中查。

緩存註解基於 aopdi,所以只有在 Container 中獲取到的對象實例才有效,比如通過 $container->getmake 方法所獲得的對象,直接 new 出來的對象無法使用。

<?php

namespace App\Services;

use App\Models\User;
use Hyperf\Cache\Annotation\Cacheable;

class UserService
{
    #[Cacheable(prefix: "user", ttl: 9000, listener: "user-update")]
    public function user($id)
    {
        $user = User::query()->where('id',$id)->first();

        if($user){
            return $user->toArray();
        }

        return null;
    }
}

清理 #[Cacheable] 生成的緩存

當然,如果我們數據庫中的數據改變了,如何刪除緩存呢?這裏就需要用到後面的監聽器。下面新建一個 Service 提供一方法,來幫我們處理緩存。

<?php

declare(strict_types=1);

namespace App\Service;

use Hyperf\Di\Annotation\Inject;
use Hyperf\Cache\Listener\DeleteListenerEvent;
use Psr\EventDispatcher\EventDispatcherInterface;

class SystemService
{
    #[Inject]
    protected EventDispatcherInterface $dispatcher;

    public function flushCache($userId)
    {
        $this->dispatcher->dispatch(new DeleteListenerEvent('user-update', [$userId]));

        return true;
    }
}

當我們自定義了 Cacheablevalue 時,比如以下情況。

<?php

declare(strict_types=1);

namespace App\Service\Cache;

use Hyperf\Cache\Annotation\Cacheable;

class DemoService
{

    #[Cacheable(prefix: "cache", value: "_#{id}", listener: "user-update")]
    public function getCache(int $id)
    {
        return $id . '_' . uniqid();
    }
}

則需要對應修改 DeleteListenerEvent 構造函數中的 $arguments 變量,具體代碼如下。

<?php

declare(strict_types=1);

namespace App\Service;

use Hyperf\Di\Annotation\Inject;
use Hyperf\Cache\Listener\DeleteListenerEvent;
use Psr\EventDispatcher\EventDispatcherInterface;

class SystemService
{
    #[Inject]
    protected EventDispatcherInterface $dispatcher;

    public function flushCache($userId)
    {
        $this->dispatcher->dispatch(new DeleteListenerEvent('user-update', ['id' => $userId]));

        return true;
    }
}

註解介紹

Cacheable

例如以下配置,緩存前綴為 user, 超時時間為 7200, 刪除事件名為 USER_CACHE。生成對應緩存 KEY 為 c:user:1

<?php

declare(strict_types=1);

namespace App\Service;

use App\Models\User;
use Hyperf\Cache\Annotation\Cacheable;

class UserService
{
    #[Cacheable(prefix: "user", ttl: 7200, listener: "USER_CACHE")]
    public function user(int $id): array
    {
        $user = User::query()->find($id);

        return [
            'user' => $user->toArray(),
            'uuid' => $this->unique(),
        ];
    }
}

當設置 value 後,框架會根據設置的規則,進行緩存 KEY 鍵命名。如下實例,當 $user->id = 1 時,緩存 KEYc:userBook:_1

<?php

declare(strict_types=1);

namespace App\Service;

use App\Models\User;
use Hyperf\Cache\Annotation\Cacheable;

class UserBookService
{
    #[Cacheable(prefix: "userBook", ttl: 6666, value: "_#{user.id}")]
    public function userBook(User $user): array
    {
        return [
            'book' => $user->book->toArray(),
            'uuid' => $this->unique(),
        ];
    }
}

CacheAhead

例如以下配置,緩存前綴為 user, 超時時間為 7200, 生成對應緩存 KEY 為 c:user:1,並且在 7200 - 600 秒的時候,每 10 秒進行一次緩存初始化,直到首次成功。

<?php

declare(strict_types=1);

namespace App\Service;

use App\Models\User;
use Hyperf\Cache\Annotation\CacheAhead;

class UserService
{
    #[CacheAhead(prefix: "user", ttl: 7200, aheadSeconds: 600, lockSeconds: 10)]
    public function user(int $id): array
    {
        $user = User::query()->find($id);

        return [
            'user' => $user->toArray(),
            'uuid' => $this->unique(),
        ];
    }
}

當設置 value 後,框架會根據設置的規則,進行緩存 KEY 鍵命名。如下實例,當 $user->id = 1 時,緩存 KEYc:userBook:_1

<?php

declare(strict_types=1);

namespace App\Service;

use App\Models\User;
use Hyperf\Cache\Annotation\Cacheable;

class UserBookService
{
    #[Cacheable(prefix: "userBook", ttl: 6666, value: "_#{user.id}")]
    public function userBook(User $user): array
    {
        return [
            'book' => $user->book->toArray(),
            'uuid' => $this->unique(),
        ];
    }
}

CachePut

CachePut 不同於 Cacheable,它每次調用都會執行函數體,然後再對緩存進行重寫。所以當我們想更新緩存時,可以調用相關方法。

<?php

declare(strict_types=1);

namespace App\Service;

use App\Models\User;
use Hyperf\Cache\Annotation\CachePut;

class UserService
{
    #[CachePut(prefix: "user", ttl: 3601)]
    public function updateUser(int $id)
    {
        $user = User::query()->find($id);
        $user->name = 'HyperfDoc';
        $user->save();

        return [
            'user' => $user->toArray(),
            'uuid' => $this->unique(),
        ];
    }
}

CacheEvict

CacheEvict 更容易理解了,當執行方法體後,會主動清理緩存。

<?php

declare(strict_types=1);

namespace App\Service;

use Hyperf\Cache\Annotation\CacheEvict;

class UserBookService
{
    #[CacheEvict(prefix: "userBook", value: "_#{id}")]
    public function updateUserBook(int $id)
    {
        return true;
    }
}

緩存驅動

Redis 驅動

Hyperf\Cache\Driver\RedisDriver 會把緩存數據存放到 Redis 中,需要用户配置相應的 Redis 配置。此方式為默認方式。

協程內存驅動

如果您需要將數據緩存到 Context 中,可以嘗試此驅動。例如以下應用場景 Demo::get 會在多個地方調用多次,但是又不想每次都到 Redis 中進行查詢。

<?php
use Hyperf\Cache\Annotation\Cacheable;

class Demo
{    
    public function get($userId, $id)
    {
        return $this->getArray($userId)[$id] ?? 0;
    }

    #[Cacheable(prefix: "test", group: "co")]
    public function getArray(int $userId): array
    {
        return $this->redis->hGetAll($userId);
    }
}

對應配置如下:

<?php

return [
    'co' => [
        'driver' => Hyperf\Cache\Driver\CoroutineMemoryDriver::class,
        'packer' => Hyperf\Utils\Packer\PhpSerializerPacker::class,
    ],
];