缓存系统

    Laravel 为各种后端缓存提供丰富而统一的 API,其配置信息位于 文件中。在该文件中你可以指定应用默认使用哪个缓存驱动。Laravel 支持当前流行的后端缓存,例如 和 Redis

    缓存配置文件还包含各种其他选项,这些选项都记录在文件中,因此请确保阅读这些选项。默认情况下,Laravel 配置为使用 file 缓存驱动,它将序列化的缓存对象存储在文件系统中。对于大型应用,建议您使用更强大的驱动程序,例如 Memcached 或 Redis。你甚至可以为同一个驱动程序配置多个缓存配置。

    数据库

    当使用 database 缓存驱动时,你需要配置一个表来存放缓存数据。下面是构建缓存数据表结构的 Schema 声明示例:

    Memcached

    使用 Memcached 驱动需要安装 Memcached PECL 扩展包 。你可以把所有的 Memcached 服务器都列在 config/cache.php 配置文件中:

    1. 'memcached' => [
    2. [
    3. 'host' => '127.0.0.1',
    4. 'port' => 11211,
    5. 'weight' => 100
    6. ],
    7. ],

    你可以将 host 选项设置为 UNIX socket 路径。如果你这样配置了, port 选项应该设置为 0

    1. 'memcached' => [
    2. [
    3. 'host' => '/var/run/memcached/memcached.sock',
    4. 'port' => 0,
    5. 'weight' => 100
    6. ],
    7. ],

    Redis

    在使用 Laravel 的 Redis 缓存之前,你需要通过 Composer 安装 predis/predis 扩展包 (~1.0) 或者使用 PECL 安装 PhpRedis PHP扩展。

    如需了解更多关于 Redis 的配置,请参考 Laravel Redis 文档

    获取缓存实例

    Illuminate\Contracts\Cache\FactoryIlluminate\Contracts\Cache\Repository 契约 提供了 Laravel 缓存服务的访问机制。 Factory 契约为你的应用程序定义了访问所有缓存驱动的机制。 Repository 契约通常是由你的 cache 配置文件指定的默认缓存驱动实现的。

    不过,你也可以使用 Cache Facade,我们将在后续的文档中介绍。 Cache Facade 为 Laravel 缓存契约底层的实现提供了方便又简洁的方法:

    1. <?php
    2. namespace App\Http\Controllers;
    3. use Illuminate\Support\Facades\Cache;
    4. class UserController extends Controller
    5. {
    6. /**
    7. * 展示应用的所有用户列表。
    8. *
    9. * @return Response
    10. */
    11. public function index()
    12. {
    13. $value = Cache::get('key');
    14. //
    15. }
    16. }

    访问多个缓存存储

    使用 Cache Facade,你可以通过 store 方法来访问各种缓存存储。传入 store 方法的键应该对应 cache 配置信息文件中的 stores 配置数组中所列的存储之一:

    1. $value = Cache::store('file')->get('foo');
    2. Cache::store('redis')->put('bar', 'baz', 600); // 10 分钟

    从缓存中获取数据

    Cache Facade 的 get 方法是用来从缓存中获取数据的方法。如果该数据在缓存中不存在,那么该方法将返回 null 。正如你想的那样,你也可以向 get 方法传递第二个参数,用来指定如果查找的数据不存在时你希望返回的默认值:

    1. $value = Cache::get('key');
    2. $value = Cache::get('key', 'default');

    你甚至可以传递 Closure 作为默认值。如果指定的数据在缓存中不存在,将返回 Closure 的结果。传递闭包的方法允许你从数据库或其他外部服务中获取默认值:

    1. $value = Cache::get('key', function () {
    2. return DB::table(...)->get();
    3. });

    检查缓存项是否存在

    has 方法可以用于判断缓存项是否存在。如果为 nullfalse 则该方法将会返回 false

    1. if (Cache::has('key')) {
    2. //
    3. }

    递增与递减值

    increment 和 方法可以用来调整缓存中整数项的值。这两个方法都可以传入第二个可选参数,这个参数用来指明要递增或递减的数量:

    1. Cache::increment('key');
    2. Cache::increment('key', $amount);
    3. Cache::decrement('key');
    4. Cache::decrement('key', $amount);

    获取和存储

    有时你可能想从缓存中获取一个数据,而当请求的缓存项不存在时,程序能为你存储一个默认值。例如,你可能想从缓存中获取所有用户,当缓存中不存在这些用户时,程序将从数据库将这些用户取出并放入缓存。你可以使用 Cache::remember 方法来实现:

    1. $value = Cache::remember('users', $seconds, function () {
    2. return DB::table('users')->get();
    3. });

    如果缓存中不存在你想要的数据时,则传递给 remember 方法的 闭包 将被执行,然后将其结果返回并放置到缓存中。

    你可以使用 rememberForever 方法从缓存中获取数据或者永久存储它:

    1. $value = Cache::rememberForever('users', function () {
    2. return DB::table('users')->get();
    3. });

    获取和删除

    1. $value = Cache::pull('key');

    在缓存中存储数据

    你可以使用 Cache Facade 的 put 方法将数据存储到缓存中:

    如果缓存的过期时间没有传递给 put 方法, 则缓存将永久有效:

    1. Cache::put('key', 'value');

    除了以整数形式传递过期时间的秒数,你还可以传递一个 DateTime 实例来表示该数据的过期时间:

    1. Cache::put('key', 'value', now()->addMinutes(10));

    只存储没有的数据

    add 方法将只存储缓存中不存在的数据。如果存储成功,将返回 true ,否则返回 false

    1. Cache::add('key', 'value', $seconds);

    数据永久存储

    forever 方法可用于持久化将数据存储到缓存中。因为这些数据不会过期,所以必须通过 forget 方法从缓存中手动删除它们:

    1. Cache::forever('key', 'value');

    Tip:如果你使用 Memcached 驱动,当缓存数据达到存储上限时,「永久存储」 的数据可能会被删除。

    你可以使用 forget 方法从缓存中删除这些数据:

    1. Cache::forget('key');

    你也可以通过提供零或者负的TTL值删除这些数据:

    1. Cache::put('key', 'value', 0);
    2. Cache::put('key', 'value', -5);

    你可以使用 flush 方法清空所有的缓存:

    1. Cache::flush();

    原子锁

    注意:要使用该特性,你的应用必须使用 memcacheddynamodbredis 缓存驱动作为你应用的默认缓存驱动。此外,所有服务器必须与同一中央缓存服务器进行通信。

    原子锁允许对分布式锁进行操作而不必担心竞争条件。例如, 使用原子锁来确保在一台服务器上每次只有一个远程任务在执行。你可以使用 Cache::lock 方法来创建和管理锁:

    1. use Illuminate\Support\Facades\Cache;
    2. $lock = Cache::lock('foo', 10);
    3. if ($lock->get()) {
    4. //获取锁定10秒...
    5. $lock->release();
    6. }

    get 方法也可以接收一个闭包。在闭包执行之后,Laravel 将会自动释放锁:

    1. Cache::lock('foo')->get(function () {
    2. });

    如果你在请求时锁无法使用,你可以控制 Laravel 等待指定的秒数。如果在指定的时间限制内无法获取锁,则会抛出 Illuminate\Contracts\Cache\LockTimeoutException

    1. use Illuminate\Contracts\Cache\LockTimeoutException;
    2. $lock = Cache::lock('foo', 10);
    3. try {
    4. $lock->block(5);
    5. // 等待最多5秒后获取的锁...
    6. } catch (LockTimeoutException $e) {
    7. // 无法获取锁...
    8. } finally {
    9. optional($lock)->release();
    10. }
    11. Cache::lock('foo', 10)->block(5, function () {
    12. // 等待最多5秒后获取的锁...
    13. });

    管理跨进程的锁

    有时,你希望在一个进程中获取锁并在另外一个进程中释放它。例如,你可以在 Web 请求期间获取锁,并希望在该请求触发的队列作业结束时释放锁。在这种情况下,你应该将锁的作用域「owner token」传递给队列作业,以便作业可以使用给定的 token 重新实例化锁:

    1. // 控制器里面...
    2. $podcast = Podcast::find($id);
    3. if ($lock = Cache::lock('foo', 120)->get()) {
    4. ProcessPodcast::dispatch($podcast, $lock->owner());
    5. // ProcessPodcast Job 里面...
    6. Cache::restoreLock('foo', $this->owner)->release();

    如果你想在不尊重当前锁的所有者的情况下释放锁,你可以使用 forceRelease 方法:

    Cache 辅助函数

    除了可以使用 Cache Facade 或 外,你还可以使用全局辅助函数 cache 来获取和保存缓存数据。当 cache 函数只接收一个字符串参数的时候,它将会返回给定键对应的值:

    1. $value = cache('key');

    如果你向函数提供了一组键值对和过期时间,它将会在指定时间内缓存数据:

    1. cache(['key' => 'value'], $seconds);
    2. cache(['key' => 'value'], now()->addMinutes(10));
    1. cache()->remember('users', $seconds, function () {
    2. return DB::table('users')->get();
    3. });

    注意:缓存标记不支持使用 filedatabase 缓存驱动。此外,当使用多个缓存标记的缓存设置为「永久」时,类似 memcached 的缓存驱动性能最佳,它会自动清除旧的记录。

    写入被标记的缓存数据

    缓存标记允许你给缓存相关进行标记,以便后续清除这些缓存值。你可以通过传入标记名称的有序数组来访问标记的缓存。例如,我们可以使用标记的同时使用 put 方法设置缓存。

    1. Cache::tags(['people', 'artists'])->put('John', $john, $seconds);
    2. Cache::tags(['people', 'authors'])->put('Anne', $anne, $seconds);

    若要获取一个被标记的缓存数据,请将相同的有序标记数组传递给 tags 方法,然后调用 get 方法来获取你要检索的键:

    1. $john = Cache::tags(['people', 'artists'])->get('John');
    2. $anne = Cache::tags(['people', 'authors'])->get('Anne');

    移除被标记的缓存数据

    你可以清空有单个标记或是一组标记的所有缓存数据。例如,下面的语句会被标记为 peopleauthors 或两者都有的缓存。所以,AnneJohn 都会从缓存中被删除:

    1. Cache::tags(['people', 'authors'])->flush();

    相反,下面的语句只会删除被标记 authors 的缓存,所以 Anne 会被删除,但 John 不会:

    1. Cache::tags('authors')->flush();

    编写驱动

    要创建自定义的缓存驱动,首先需要实现 Illuminate\Contracts\Cache\Store 。因此, MongoDB 的缓存实现看起来会像这样:

    1. <?php
    2. namespace App\Extensions;
    3. use Illuminate\Contracts\Cache\Store;
    4. class MongoStore implements Store
    5. {
    6. public function get($key) {}
    7. public function many(array $keys);
    8. public function put($key, $value, $seconds) {}
    9. public function putMany(array $values, $seconds);
    10. public function increment($key, $value = 1) {}
    11. public function decrement($key, $value = 1) {}
    12. public function forever($key, $value) {}
    13. public function forget($key) {}
    14. public function flush() {}
    15. public function getPrefix() {}

    我们只需要 MongoDB 的连接来实现这些方法。关于如何实现这些方法的实例,可以参阅框架源代码中的 Illuminate\Cache\MemcachedStore 。一旦完成契约额实现后,就可以像下面这样完成自定义驱动的注册了。

    Cache::extend('mongo', function ($app) {
        return Cache::repository(new MongoStore);
    });

    注册驱动

    要使用 Laravel 来注册自定义缓存驱动,就要在 Cache Facade 上使用 extend 方法。 对 Cache::extend 的调用可以在新的 Laravel 应用程序中自带的 App\Providers\AppServiceProviderboot 方法中完成,或者你也可以创建自己的服务提供者来存放扩展,只是不要忘记在 config/app.php 的 provider 数组中注册服务提供者:

    <?php
    
    namespace App\Providers;
    
    use App\Extensions\MongoStore;
    use Illuminate\Support\Facades\Cache;
    use Illuminate\Support\ServiceProvider;
    
    class CacheServiceProvider extends ServiceProvider
    {
        /**
         * 执行服务的注册后引导。
         *
         * @return void
         */
        public function boot()
        {
            Cache::extend('mongo', function ($app) {
                return Cache::repository(new MongoStore);
            });
        }
    
        /**
         * 在容器中注册绑定。
         *
         * @return void
         */
        public function register()
        {
            //
        }
    }

    传递给 extend 方法的第一个参数是驱动程序的名称。这将与 config/cache.php 配置文件的 driver 选项相对应。第二个参数是一个应该返回 Illuminate\Cache\Repository 实例的闭包。该闭包将传递一个 服务容器$app 实例。

    一旦你的扩展程序注册后,需要将 config/cache.php 配置文件中的 driver 选项更新为你的扩展名称。

    要在每次缓存操作时执行代码,你可以监听缓存触发的 事件 。通常,你应该将这些事件监听器放在 EventServiceProvider 中:

    
    

    本文章首发在 网站上。

    本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接 我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。