Cache

hyperf/cache 提供了基于 Aspect 实现的切面缓存,也提供了实现 Psr\SimpleCache\CacheInterface 的缓存类。

安装

  1. composer require hyperf/cache

默认配置

配置 默认值 备注
driver Hyperf\Cache\Driver\RedisDriver 缓存驱动,默认为 Redis
packer Hyperf\Utils\Packer\PhpSerializer 打包器
prefix c: 缓存前缀
  1. <?php
  2. return [
  3. 'default' => [
  4. 'driver' => Hyperf\Cache\Driver\RedisDriver::class,
  5. 'packer' => Hyperf\Utils\Packer\PhpSerializerPacker::class,
  6. 'prefix' => 'c:',
  7. ],
  8. ];

使用

Simple Cache 方式

Simple Cache 也就是 PSR-16 规范,本组件适配了该规范,如果您希望使用实现 Psr\SimpleCache\CacheInterface 缓存类,比如要重写 EasyWeChat 的缓存模块,可以直接从依赖注入容器中获取 Psr\SimpleCache\CacheInterface 即可,如下所示:

  1. $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 出来的对象无法使用。

  1. <?php
  2. namespace App\Services;
  3. use App\Models\User;
  4. use Hyperf\Cache\Annotation\Cacheable;
  5. class UserService
  6. {
  7. /**
  8. * @Cacheable(prefix="user", ttl=9000, listener="user-update")
  9. */
  10. public function user($id)
  11. {
  12. $user = User::query()->where('id',$id)->first();
  13. if($user){
  14. return $user->toArray();
  15. }
  16. return null;
  17. }
  18. }

清理 @Cacheable 生成的缓存

当然,如果我们数据库中的数据改变了,如何删除缓存呢?这里就需要用到后面的监听器。下面新建一个 Service 提供一方法,来帮我们处理缓存。

  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Service;
  4. use Hyperf\Di\Annotation\Inject;
  5. use Hyperf\Cache\Listener\DeleteListenerEvent;
  6. use Psr\EventDispatcher\EventDispatcherInterface;
  7. class SystemService
  8. {
  9. /**
  10. * @Inject
  11. * @var EventDispatcherInterface
  12. */
  13. protected $dispatcher;
  14. public function flushCache($userId)
  15. {
  16. $this->dispatcher->dispatch(new DeleteListenerEvent('user-update', [$userId]));
  17. return true;
  18. }
  19. }

当我们自定义了 Cacheablevalue 时,比如以下情况。

  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Service\Cache;
  4. use Hyperf\Cache\Annotation\Cacheable;
  5. class DemoService
  6. {
  7. /**
  8. * @Cacheable(prefix="cache", value="_#{id}", listener="user-update")
  9. */
  10. public function getCache(int $id)
  11. {
  12. return $id . '_' . uniqid();
  13. }
  14. }

则需要对应修改 DeleteListenerEvent 构造函数中的 $arguments 变量,具体代码如下。

  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Service;
  4. use Hyperf\Di\Annotation\Inject;
  5. use Hyperf\Cache\Listener\DeleteListenerEvent;
  6. use Psr\EventDispatcher\EventDispatcherInterface;
  7. class SystemService
  8. {
  9. /**
  10. * @Inject
  11. * @var EventDispatcherInterface
  12. */
  13. protected $dispatcher;
  14. public function flushCache($userId)
  15. {
  16. $this->dispatcher->dispatch(new DeleteListenerEvent('user-update', ['id' => $userId]));
  17. return true;
  18. }
  19. }

注解介绍

Cacheable

例如以下配置,缓存前缀为 user, 超时时间为 7200, 删除事件名为 USER_CACHE。生成对应缓存 KEY 为 c:user:1

  1. use App\Models\User;
  2. use Hyperf\Cache\Annotation\Cacheable;
  3. /**
  4. * @Cacheable(prefix="user", ttl=7200, listener="USER_CACHE")
  5. */
  6. public function user(int $id): array
  7. {
  8. $user = User::query()->find($id);
  9. return [
  10. 'user' => $user->toArray(),
  11. 'uuid' => $this->unique(),
  12. ];
  13. }

当设置 value 后,框架会根据设置的规则,进行缓存 KEY 键命名。如下实例,当 $user->id = 1 时,缓存 KEYc:userBook:_1

  1. use App\Models\User;
  2. use Hyperf\Cache\Annotation\Cacheable;
  3. /**
  4. * @Cacheable(prefix="userBook", ttl=6666, value="_#{user.id}")
  5. */
  6. public function userBook(User $user): array
  7. {
  8. return [
  9. 'book' => $user->book->toArray(),
  10. 'uuid' => $this->unique(),
  11. ];
  12. }

CachePut

CachePut 不同于 Cacheable,它每次调用都会执行函数体,然后再对缓存进行重写。所以当我们想更新缓存时,可以调用相关方法。

  1. use App\Models\User;
  2. use Hyperf\Cache\Annotation\CachePut;
  3. /**
  4. * @CachePut(prefix="user", ttl=3601)
  5. */
  6. public function updateUser(int $id)
  7. {
  8. $user = User::query()->find($id);
  9. $user->name = 'HyperfDoc';
  10. $user->save();
  11. return [
  12. 'user' => $user->toArray(),
  13. 'uuid' => $this->unique(),
  14. ];
  15. }

CacheEvict

CacheEvict 更容易理解了,当执行方法体后,会主动清理缓存。

  1. use Hyperf\Cache\Annotation\CacheEvict;
  2. /**
  3. * @CacheEvict(prefix="userBook", value="_#{id}")
  4. */
  5. public function updateUserBook(int $id)
  6. {
  7. return true;
  8. }

缓存驱动

Redis 驱动

Hyperf\Cache\Driver\RedisDriver 会把缓存数据存放到 Redis 中,需要用户配置相应的 Redis 配置。此方式为默认方式。

协程内存驱动

如果您需要将数据缓存到 Context 中,可以尝试此驱动。例如以下应用场景 Demo::get 会在多个地方调用多次,但是又不想每次都到 Redis 中进行查询。

  1. <?php
  2. use Hyperf\Cache\Annotation\Cacheable;
  3. class Demo {
  4. public function get($userId, $id)
  5. {
  6. return $this->getArray($userId)[$id] ?? 0;
  7. }
  8. /**
  9. * @Cacheable(prefix="test", group="co")
  10. */
  11. public function getArray(int $userId): array
  12. {
  13. return $this->redis->hGetAll($userId);
  14. }
  15. }

对应配置如下:

  1. <?php
  2. return [
  3. 'co' => [
  4. 'driver' => Hyperf\Cache\Driver\CoroutineMemoryDriver::class,
  5. 'packer' => Hyperf\Utils\Packer\PhpSerializerPacker::class,
  6. ],
  7. ];