Co-authored-by: 张城铭 <z@hyperf.io>
8.5 KiB
Cache
hyperf/cache provides aspect cache based on Aspect
implementation, and also provides cache classes that implement Psr\SimpleCache\CacheInterface
.
Install
composer require hyperf/cache
Default allocation
Configuration | Default value | Remark |
---|---|---|
driver | Hyperf\Cache\Driver\RedisDriver | Cache driver, default is Redis |
packer | Hyperf\Codec\Packer\PhpSerializerPacker | Packager |
prefix | c: | Cache prefix |
skip_cache_results | [] | Certain results are not cached |
<?php
return [
'default' => [
'driver' => Hyperf\Cache\Driver\RedisDriver::class,
'packer' => Hyperf\Codec\Packer\PhpSerializerPacker::class,
'prefix' => 'c:',
'skip_cache_results' => [],
],
];
Use
Simple Cache method
Simple Cache is the PSR-16 specification. This component adapts to the specification. If you want to use Psr\SimpleCache\CacheInterface
Cache class, for example, if you want to rewrite the cache module of EasyWeChat
, you can get Psr\SimpleCache\CacheInterface
directly from the dependency injection container, as shown below:
$cache = $container->get(\Psr\SimpleCache\CacheInterface::class);
Annotation method
The component provides Hyperf\Cache\Annotation\Cacheable
annotation, which acts on class methods and can configure the corresponding cache prefix, expiration time, listener and cache group.
For example, UserService provides a user method that can query user information corresponding to id. When the Hyperf\Cache\Annotation\Cacheable
annotation is added, the corresponding Redis cache will be automatically generated. The key value is user:id
and the timeout is 9000
seconds. When querying for the first time, it will be checked from the database, and for subsequent queries, it will be checked from the cache.
<?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;
}
}
Clean the cache generated by #[Cacheable]
We provide two annotations, CachePut
and CacheEvict
, to implement cache update and cache clearing operations.
Of course, we can also delete the cache through events. Let's create a new Service to provide a method to help us handle caching.
However, we recommend users to use annotation processing instead of listeners.
<?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;
}
}
When we customize the value
of Cacheable
, such as the following situation.
<?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();
}
}
You need to modify the $arguments
variable in the DeleteListenerEvent
constructor accordingly. The specific code is as follows.
<?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;
}
}
Introduction to annotations
Cacheable
For example, in the following configuration, the cache prefix is user
, the timeout is 7200
, and the deletion event name is USER_CACHE
. The corresponding cache KEY is generated as 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(),
];
}
}
When value
is set, the framework will cache the KEY
key naming according to the set rules. In the following example, when $user->id = 1
, the cached KEY
is c:userBook:_1
This configuration also supports other types of cache annotations described below
<?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
For example, in the following configuration, the cache prefix is user
, the timeout is 7200
, the corresponding cache KEY generated is c:user:1
, and the cache is initialized every 10 seconds from 7200 to 600 seconds until the first time success.
<?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(),
];
}
}
CachePut
CachePut
is different from Cacheable
in that it executes the function body every time it is called and then rewrites the cache. So when we want to update the cache, we can call the relevant methods.
<?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 is easier to understand. When the method body is executed, the cache will be actively cleaned.
<?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;
}
}
Cache driver
Redis driver
Hyperf\Cache\Driver\RedisDriver
will store cache data in Redis
, and users need to configure the corresponding Redis configuration
. This mode is the default mode.
Process memory driver
If you need to cache data into memory, you can try this driver. The configuration is as follows:
<?php
return [
'memory' => [
'driver' => Hyperf\Cache\Driver\MemoryDriver::class,
],
];
Coroutine memory driver
If you need to cache data into Context
, you can try this driver. For example, in the following application scenario, Demo::get
will be called multiple times in multiple places, but you do not want to query Redis
every time.
<?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);
}
}
The corresponding configuration is as follows:
<?php
return [
'co' => [
'driver' => Hyperf\Cache\Driver\CoroutineMemoryDriver::class,
'packer' => Hyperf\Codec\Packer\PhpSerializerPacker::class,
],
];