hyperf/docs/zh-cn/cache.md

357 lines
8.2 KiB
Markdown
Raw Normal View History

2019-03-08 12:04:46 +08:00
# Cache
[hyperf/cache](https://github.com/hyperf/cache) 提供了基于 `Aspect` 实现的切面缓存,也提供了实现 `Psr\SimpleCache\CacheInterface` 的缓存类。
2019-03-08 12:04:46 +08:00
2019-03-21 13:42:28 +08:00
## 安装
```
composer require hyperf/cache
```
2019-03-08 12:04:46 +08:00
## 默认配置
2019-03-22 17:41:09 +08:00
| 配置 | 默认值 | 备注 |
|:------:|:----------------------------------------:|:---------------------:|
2019-11-12 19:46:54 +08:00
| driver | Hyperf\Cache\Driver\RedisDriver | 缓存驱动,默认为 Redis |
2019-05-24 15:37:46 +08:00
| packer | Hyperf\Utils\Packer\PhpSerializer | 打包器 |
| 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-03 17:46:55 +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-10-12 18:25:18 +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-03-22 17:41:09 +08:00
### 注解方式
2019-03-21 15:04:42 +08:00
组件提供 `Hyperf\Cache\Annotation\Cacheable` 注解,作用于类方法,可以配置对应的缓存前缀、失效时间、监听器和缓存组。
2019-11-12 19:46:54 +08:00
例如UserService 提供一个 user 方法,可以查询对应 id 的用户信息。当加上 `Hyperf\Cache\Annotation\Cacheable` 注解后,会自动生成对应的 Redis 缓存key 值为 `user:id` ,超时时间为 `9000` 秒。首次查询时,会从数据库中查,后面查询时,会从缓存中查。
2019-03-08 12:04:46 +08:00
2019-12-12 16:41:17 +08:00
> 缓存注解基于 [aop](zh-cn/aop.md) 和 [di](zh-cn/di.md),所以只有在 `Container` 中获取到的对象实例才有效,比如通过 `$container->get` 和 `make` 方法所获得的对象,直接 `new` 出来的对象无法使用。
2019-07-29 17:01:43 +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
{
#[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:13:43 +08:00
### 清理 `#[Cacheable]` 生成的缓存
2019-03-08 12:04:46 +08:00
当然,如果我们数据库中的数据改变了,如何删除缓存呢?这里就需要用到后面的监听器。下面新建一个 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
{
#[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-11-26 17:19:36 +08:00
当我们自定义了 `Cacheable``value` 时,比如以下情况。
```php
<?php
declare(strict_types=1);
namespace App\Service\Cache;
use Hyperf\Cache\Annotation\Cacheable;
class DemoService
{
#[Cacheable(prefix: "cache", value: "_#{id}", listener: "user-update")]
2019-11-26 17:19:36 +08:00
public function getCache(int $id)
{
return $id . '_' . uniqid();
}
}
```
则需要对应修改 `DeleteListenerEvent` 构造函数中的 `$arguments` 变量,具体代码如下。
```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
{
#[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;
}
}
```
## 注解介绍
### Cacheable
2019-10-12 18:25:18 +08:00
例如以下配置,缓存前缀为 `user`, 超时时间为 `7200`, 删除事件名为 `USER_CACHE`。生成对应缓存 KEY 为 `c:user:1`
```php
<?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(),
];
}
}
```
2019-10-12 18:25:18 +08:00
当设置 `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;
2022-11-22 12:29:12 +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;
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
2019-10-12 18:25:18 +08:00
`CachePut` 不同于 `Cacheable`,它每次调用都会执行函数体,然后再对缓存进行重写。所以当我们想更新缓存时,可以调用相关方法。
```php
<?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
<?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;
}
}
```
2019-07-24 10:07:56 +08:00
## 缓存驱动
2019-11-12 19:46:54 +08:00
### Redis 驱动
2019-07-24 10:07:56 +08:00
2019-11-12 19:46:54 +08:00
`Hyperf\Cache\Driver\RedisDriver` 会把缓存数据存放到 `Redis` 中,需要用户配置相应的 `Redis 配置`。此方式为默认方式。
2019-07-24 10:07:56 +08:00
### 协程内存驱动
2019-07-24 15:24:11 +08:00
如果您需要将数据缓存到 `Context` 中,可以尝试此驱动。例如以下应用场景 `Demo::get` 会在多个地方调用多次,但是又不想每次都到 `Redis` 中进行查询。
2019-07-24 10:07:56 +08:00
```php
<?php
use Hyperf\Cache\Annotation\Cacheable;
class Demo
{
2019-07-24 10:07:56 +08:00
public function get($userId, $id)
{
return $this->getArray($userId)[$id] ?? 0;
}
#[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);
}
}
```
对应配置如下:
```php
<?php
return [
'co' => [
'driver' => Hyperf\Cache\Driver\CoroutineMemoryDriver::class,
'packer' => Hyperf\Utils\Packer\PhpSerializerPacker::class,
],
];
```