2019-03-08 12:04:46 +08:00
|
|
|
|
# Cache
|
|
|
|
|
|
2019-12-12 16:24:04 +08:00
|
|
|
|
[hyperf/cache](https://github.com/hyperf/cache) 提供了基於 `Aspect` 實現的切面快取,也提供了實現 `Psr\SimpleCache\CacheInterface` 的快取類。
|
2019-03-08 12:04:46 +08:00
|
|
|
|
|
2019-12-12 16:24:04 +08:00
|
|
|
|
## 安裝
|
2019-03-21 13:42:28 +08:00
|
|
|
|
```
|
|
|
|
|
composer require hyperf/cache
|
|
|
|
|
```
|
|
|
|
|
|
2019-12-12 16:24:04 +08:00
|
|
|
|
## 預設配置
|
2019-03-08 12:04:46 +08:00
|
|
|
|
|
2019-12-12 16:24:04 +08:00
|
|
|
|
| 配置 | 預設值 | 備註 |
|
2019-03-22 17:41:09 +08:00
|
|
|
|
|:------:|:----------------------------------------:|:---------------------:|
|
2019-12-12 16:24:04 +08:00
|
|
|
|
| driver | Hyperf\Cache\Driver\RedisDriver | 快取驅動,預設為 Redis |
|
2019-05-24 15:37:46 +08:00
|
|
|
|
| packer | Hyperf\Utils\Packer\PhpSerializer | 打包器 |
|
2019-12-12 16:24:04 +08:00
|
|
|
|
| prefix | c: | 快取字首 |
|
2019-03-22 17:41:09 +08:00
|
|
|
|
|
2019-03-19 14:52:21 +08:00
|
|
|
|
```php
|
2019-03-08 12:04:46 +08:00
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
return [
|
|
|
|
|
'default' => [
|
|
|
|
|
'driver' => Hyperf\Cache\Driver\RedisDriver::class,
|
2020-06-16 01:43:41 +08:00
|
|
|
|
'packer' => Hyperf\Utils\Packer\PhpSerializerPacker::class,
|
2019-03-22 17:41:09 +08:00
|
|
|
|
'prefix' => 'c:',
|
2019-03-08 12:04:46 +08:00
|
|
|
|
],
|
|
|
|
|
];
|
2019-03-19 14:52:21 +08:00
|
|
|
|
```
|
2019-03-08 12:04:46 +08:00
|
|
|
|
|
|
|
|
|
## 使用
|
|
|
|
|
|
2019-10-12 18:25:18 +08:00
|
|
|
|
### Simple Cache 方式
|
2019-05-24 15:39:16 +08:00
|
|
|
|
|
2019-12-12 16:24:04 +08:00
|
|
|
|
Simple Cache 也就是 [PSR-16](https://www.php-fig.org/psr/psr-16/) 規範,本元件適配了該規範,如果您希望使用實現 `Psr\SimpleCache\CacheInterface` 快取類,比如要重寫 `EasyWeChat` 的快取模組,可以直接從依賴注入容器中獲取 `Psr\SimpleCache\CacheInterface` 即可,如下所示:
|
2019-05-24 15:39:16 +08:00
|
|
|
|
|
|
|
|
|
```php
|
|
|
|
|
|
2019-10-12 18:25:18 +08:00
|
|
|
|
$cache = $container->get(\Psr\SimpleCache\CacheInterface::class);
|
2019-05-24 15:39:16 +08:00
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
2019-12-12 16:24:04 +08:00
|
|
|
|
### 註解方式
|
2019-03-22 17:41:09 +08:00
|
|
|
|
|
2019-12-12 16:24:04 +08:00
|
|
|
|
元件提供 `Hyperf\Cache\Annotation\Cacheable` 註解,作用於類方法,可以配置對應的快取字首、失效時間、監聽器和快取組。
|
|
|
|
|
例如,UserService 提供一個 user 方法,可以查詢對應 id 的使用者資訊。當加上 `Hyperf\Cache\Annotation\Cacheable` 註解後,會自動生成對應的 Redis 快取,key 值為 `user:id` ,超時時間為 `9000` 秒。首次查詢時,會從資料庫中查,後面查詢時,會從快取中查。
|
2019-03-08 12:04:46 +08:00
|
|
|
|
|
2019-03-19 14:52:21 +08:00
|
|
|
|
```php
|
2019-03-08 12:04:46 +08:00
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace App\Services;
|
|
|
|
|
|
|
|
|
|
use App\Models\User;
|
|
|
|
|
use Hyperf\Cache\Annotation\Cacheable;
|
|
|
|
|
|
|
|
|
|
class UserService
|
|
|
|
|
{
|
2021-12-01 16:19:47 +08:00
|
|
|
|
#[Cacheable(prefix: "user", ttl: 9000, listener: "user-update")]
|
2019-03-08 12:04:46 +08:00
|
|
|
|
public function user($id)
|
|
|
|
|
{
|
2019-04-05 10:01:15 +08:00
|
|
|
|
$user = User::query()->where('id',$id)->first();
|
2019-03-08 12:04:46 +08:00
|
|
|
|
|
|
|
|
|
if($user){
|
|
|
|
|
return $user->toArray();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-03-19 14:52:21 +08:00
|
|
|
|
```
|
2019-03-08 12:04:46 +08:00
|
|
|
|
|
2023-01-03 07:32:23 +08:00
|
|
|
|
### 清理 `#[Cacheable]` 生成的快取
|
2019-03-08 12:04:46 +08:00
|
|
|
|
|
2023-08-16 16:20:08 +08:00
|
|
|
|
我們提供了 `CachePut` 和 `CacheEvict` 兩個註解,來實現更新快取和清除快取操作。
|
|
|
|
|
|
|
|
|
|
當然,我們也可以透過事件來刪除快取。下面新建一個 Service 提供一方法,來幫我們處理快取。
|
|
|
|
|
|
|
|
|
|
> 不過我們更加推薦使用者使用註解處理,而非監聽器
|
2019-03-08 12:04:46 +08:00
|
|
|
|
|
2019-03-19 14:52:21 +08:00
|
|
|
|
```php
|
2019-03-08 12:04:46 +08:00
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
|
|
namespace App\Service;
|
|
|
|
|
|
|
|
|
|
use Hyperf\Di\Annotation\Inject;
|
|
|
|
|
use Hyperf\Cache\Listener\DeleteListenerEvent;
|
|
|
|
|
use Psr\EventDispatcher\EventDispatcherInterface;
|
|
|
|
|
|
|
|
|
|
class SystemService
|
|
|
|
|
{
|
2021-12-01 16:19:47 +08:00
|
|
|
|
#[Inject]
|
|
|
|
|
protected EventDispatcherInterface $dispatcher;
|
2019-03-08 12:04:46 +08:00
|
|
|
|
|
|
|
|
|
public function flushCache($userId)
|
|
|
|
|
{
|
|
|
|
|
$this->dispatcher->dispatch(new DeleteListenerEvent('user-update', [$userId]));
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-03-22 17:41:09 +08:00
|
|
|
|
```
|
|
|
|
|
|
2019-12-12 16:24:04 +08:00
|
|
|
|
當我們自定義了 `Cacheable` 的 `value` 時,比如以下情況。
|
2019-11-26 17:19:36 +08:00
|
|
|
|
|
|
|
|
|
```php
|
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
|
|
namespace App\Service\Cache;
|
|
|
|
|
|
|
|
|
|
use Hyperf\Cache\Annotation\Cacheable;
|
|
|
|
|
|
|
|
|
|
class DemoService
|
|
|
|
|
{
|
2021-12-01 16:19:47 +08:00
|
|
|
|
|
|
|
|
|
#[Cacheable(prefix: "cache", value: "_#{id}", listener: "user-update")]
|
2019-11-26 17:19:36 +08:00
|
|
|
|
public function getCache(int $id)
|
|
|
|
|
{
|
|
|
|
|
return $id . '_' . uniqid();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2019-12-12 16:24:04 +08:00
|
|
|
|
則需要對應修改 `DeleteListenerEvent` 建構函式中的 `$arguments` 變數,具體程式碼如下。
|
2019-11-26 17:19:36 +08:00
|
|
|
|
|
|
|
|
|
```php
|
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
|
|
namespace App\Service;
|
|
|
|
|
|
|
|
|
|
use Hyperf\Di\Annotation\Inject;
|
|
|
|
|
use Hyperf\Cache\Listener\DeleteListenerEvent;
|
|
|
|
|
use Psr\EventDispatcher\EventDispatcherInterface;
|
|
|
|
|
|
|
|
|
|
class SystemService
|
|
|
|
|
{
|
2021-12-01 16:19:47 +08:00
|
|
|
|
#[Inject]
|
|
|
|
|
protected EventDispatcherInterface $dispatcher;
|
2019-11-26 17:19:36 +08:00
|
|
|
|
|
|
|
|
|
public function flushCache($userId)
|
|
|
|
|
{
|
|
|
|
|
$this->dispatcher->dispatch(new DeleteListenerEvent('user-update', ['id' => $userId]));
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2019-12-12 16:24:04 +08:00
|
|
|
|
## 註解介紹
|
2019-05-09 15:04:07 +08:00
|
|
|
|
|
|
|
|
|
### Cacheable
|
|
|
|
|
|
2019-12-12 16:24:04 +08:00
|
|
|
|
例如以下配置,快取字首為 `user`, 超時時間為 `7200`, 刪除事件名為 `USER_CACHE`。生成對應快取 KEY 為 `c:user:1`。
|
2019-05-09 15:04:07 +08:00
|
|
|
|
|
|
|
|
|
```php
|
2021-12-01 16:19:47 +08:00
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
|
|
namespace App\Service;
|
|
|
|
|
|
2019-05-09 15:04:07 +08:00
|
|
|
|
use App\Models\User;
|
|
|
|
|
use Hyperf\Cache\Annotation\Cacheable;
|
|
|
|
|
|
2021-12-01 16:19:47 +08:00
|
|
|
|
class UserService
|
2019-05-09 15:04:07 +08:00
|
|
|
|
{
|
2021-12-01 16:19:47 +08:00
|
|
|
|
#[Cacheable(prefix: "user", ttl: 7200, listener: "USER_CACHE")]
|
|
|
|
|
public function user(int $id): array
|
|
|
|
|
{
|
|
|
|
|
$user = User::query()->find($id);
|
2019-05-09 15:04:07 +08:00
|
|
|
|
|
2021-12-01 16:19:47 +08:00
|
|
|
|
return [
|
|
|
|
|
'user' => $user->toArray(),
|
|
|
|
|
'uuid' => $this->unique(),
|
|
|
|
|
];
|
|
|
|
|
}
|
2019-05-09 15:04:07 +08:00
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2019-12-12 16:24:04 +08:00
|
|
|
|
當設定 `value` 後,框架會根據設定的規則,進行快取 `KEY` 鍵命名。如下例項,當 `$user->id = 1` 時,快取 `KEY` 為 `c:userBook:_1`
|
2019-05-09 15:04:07 +08:00
|
|
|
|
|
|
|
|
|
```php
|
2021-12-01 16:19:47 +08:00
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
|
|
namespace App\Service;
|
|
|
|
|
|
2019-05-09 15:04:07 +08:00
|
|
|
|
use App\Models\User;
|
|
|
|
|
use Hyperf\Cache\Annotation\Cacheable;
|
|
|
|
|
|
2022-11-23 11:54:10 +08:00
|
|
|
|
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
|
|
|
|
|
<?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` 時,快取 `KEY` 為 `c:userBook:_1`
|
|
|
|
|
|
|
|
|
|
```php
|
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
|
|
namespace App\Service;
|
|
|
|
|
|
|
|
|
|
use App\Models\User;
|
|
|
|
|
use Hyperf\Cache\Annotation\Cacheable;
|
|
|
|
|
|
2021-12-01 16:19:47 +08:00
|
|
|
|
class UserBookService
|
2019-05-09 15:04:07 +08:00
|
|
|
|
{
|
2021-12-01 16:19:47 +08:00
|
|
|
|
#[Cacheable(prefix: "userBook", ttl: 6666, value: "_#{user.id}")]
|
|
|
|
|
public function userBook(User $user): array
|
|
|
|
|
{
|
|
|
|
|
return [
|
|
|
|
|
'book' => $user->book->toArray(),
|
|
|
|
|
'uuid' => $this->unique(),
|
|
|
|
|
];
|
|
|
|
|
}
|
2019-05-09 15:04:07 +08:00
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### CachePut
|
|
|
|
|
|
2019-12-12 16:24:04 +08:00
|
|
|
|
`CachePut` 不同於 `Cacheable`,它每次呼叫都會執行函式體,然後再對快取進行重寫。所以當我們想更新快取時,可以呼叫相關方法。
|
2019-05-09 15:04:07 +08:00
|
|
|
|
|
|
|
|
|
```php
|
2021-12-01 16:19:47 +08:00
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
|
|
namespace App\Service;
|
|
|
|
|
|
2019-05-09 15:04:07 +08:00
|
|
|
|
use App\Models\User;
|
|
|
|
|
use Hyperf\Cache\Annotation\CachePut;
|
|
|
|
|
|
2021-12-01 16:19:47 +08:00
|
|
|
|
class UserService
|
2019-05-09 15:04:07 +08:00
|
|
|
|
{
|
2021-12-01 16:19:47 +08:00
|
|
|
|
#[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(),
|
|
|
|
|
];
|
|
|
|
|
}
|
2019-05-09 15:04:07 +08:00
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### CacheEvict
|
|
|
|
|
|
2019-12-12 16:24:04 +08:00
|
|
|
|
CacheEvict 更容易理解了,當執行方法體後,會主動清理快取。
|
2019-05-09 15:04:07 +08:00
|
|
|
|
|
|
|
|
|
```php
|
2021-12-01 16:19:47 +08:00
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
|
|
namespace App\Service;
|
|
|
|
|
|
2019-05-09 15:04:07 +08:00
|
|
|
|
use Hyperf\Cache\Annotation\CacheEvict;
|
|
|
|
|
|
2021-12-01 16:19:47 +08:00
|
|
|
|
class UserBookService
|
2019-05-09 15:04:07 +08:00
|
|
|
|
{
|
2021-12-01 16:19:47 +08:00
|
|
|
|
#[CacheEvict(prefix: "userBook", value: "_#{id}")]
|
|
|
|
|
public function updateUserBook(int $id)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2019-05-09 15:04:07 +08:00
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2019-12-12 16:24:04 +08:00
|
|
|
|
## 快取驅動
|
2019-07-24 10:07:56 +08:00
|
|
|
|
|
2019-12-12 16:24:04 +08:00
|
|
|
|
### Redis 驅動
|
2019-07-24 10:07:56 +08:00
|
|
|
|
|
2019-12-12 16:24:04 +08:00
|
|
|
|
`Hyperf\Cache\Driver\RedisDriver` 會把快取資料存放到 `Redis` 中,需要使用者配置相應的 `Redis 配置`。此方式為預設方式。
|
2019-07-24 10:07:56 +08:00
|
|
|
|
|
2019-12-12 16:24:04 +08:00
|
|
|
|
### 協程記憶體驅動
|
2019-07-24 10:07:56 +08:00
|
|
|
|
|
2019-12-12 16:24:04 +08:00
|
|
|
|
如果您需要將資料快取到 `Context` 中,可以嘗試此驅動。例如以下應用場景 `Demo::get` 會在多個地方呼叫多次,但是又不想每次都到 `Redis` 中進行查詢。
|
2019-07-24 10:07:56 +08:00
|
|
|
|
|
|
|
|
|
```php
|
|
|
|
|
<?php
|
|
|
|
|
use Hyperf\Cache\Annotation\Cacheable;
|
|
|
|
|
|
2021-12-01 16:19:47 +08:00
|
|
|
|
class Demo
|
|
|
|
|
{
|
2019-07-24 10:07:56 +08:00
|
|
|
|
public function get($userId, $id)
|
|
|
|
|
{
|
|
|
|
|
return $this->getArray($userId)[$id] ?? 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-01 16:19:47 +08:00
|
|
|
|
#[Cacheable(prefix: "test", group: "co")]
|
2019-10-12 18:25:18 +08:00
|
|
|
|
public function getArray(int $userId): array
|
2019-07-24 10:07:56 +08:00
|
|
|
|
{
|
|
|
|
|
return $this->redis->hGetAll($userId);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2019-12-12 16:24:04 +08:00
|
|
|
|
對應配置如下:
|
2019-07-24 10:07:56 +08:00
|
|
|
|
|
|
|
|
|
```php
|
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
return [
|
|
|
|
|
'co' => [
|
|
|
|
|
'driver' => Hyperf\Cache\Driver\CoroutineMemoryDriver::class,
|
|
|
|
|
'packer' => Hyperf\Utils\Packer\PhpSerializerPacker::class,
|
|
|
|
|
],
|
|
|
|
|
];
|
|
|
|
|
```
|