缓存系统

Laravel 中文文档 · 2019-01-15 15:42:17

配置

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

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

驱动的前提条件

数据库

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

Schema::create('cache', function ($table) {
    $table->string('key')->unique();
    $table->text('value');
    $table->integer('expiration');
});

{tip} 你也可以使用 Artisan 命令 php artisan cache:table 来生成合适的迁移。

Memcached

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

'memcached' => [
    [
        'host' => '127.0.0.1',
        'port' => 11211,
        'weight' => 100
    ],
],

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

'memcached' => [
    [
        'host' => '/var/run/memcached/memcached.sock',
        'port' => 0,
        'weight' => 100
    ],
],

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 缓存契约底层的实现提供了方便又简洁的方法:

<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Cache;

class UserController extends Controller
{
    /**
     * 显示应用程序的所有用户的列表。
     *
     * @return Response
     */
    public function index()
    {
        $value = Cache::get('key');

        //
    }
}

访问多个缓存存储

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

$value = Cache::store('file')->get('foo');

Cache::store('redis')->put('bar', 'baz', 10);

从缓存中获取数据

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

$value = Cache::get('key');

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

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

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

确认项目是否存在

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

if (Cache::has('key')) {
    //
}

递增与递减值

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

Cache::increment('key');
Cache::increment('key', $amount);
Cache::decrement('key');
Cache::decrement('key', $amount);

获取和存储

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

$value = Cache::remember('users', $minutes, function () {
    return DB::table('users')->get();
});

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

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

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

获取和删除

如果你需要从缓存中获取到数据之后再删除它,你可以使用 pull 方法。和 get 方法一样,如果缓存不存在该数据,则返回 null

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

在缓存中存数数据

你可能用 Cache Facade 的 put 方法将数据存储到缓存中。当你在缓存中存放数据时,你需要使用第三个参数来设定缓存的过期时间:

Cache::put('key', 'value', $minutes);

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

$expiresAt = now()->addMinutes(10);

Cache::put('key', 'value', $expiresAt);

只存储没有的数据

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

Cache::add('key', 'value', $minutes);

数据永久存储

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

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

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

删除缓存中的数据

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

Cache::forget('key');

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

Cache::flush();

{注意} 清空缓存的方法并不会考虑缓存前缀,会将缓存中的所有内容删除。因此在清除与其他应用程序共享的缓存时,请慎重考虑。

原子锁

{note} 使用该特性,应用必须使用 memcachedredis 缓存驱动作为应用默认缓存驱动。此外,所有服务器必须与同一中央缓存服务器进行通信。

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

if (Cache::lock('foo', 10)->get()) {
    // 获取锁定10秒...

    Cache::lock('foo')->release();
}

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

Cache::lock('foo')->get(function () {
    // 锁无限期获取并自动释放...
});

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

if (Cache::lock('foo', 10)->block(5)) {
    // 等待最多5秒后获取锁定...
}

Cache::lock('foo', 10)->block(5, function () {
    // 等待最多5秒后获取锁定...
});

Cache 辅助函数

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

$value = cache('key');

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

cache(['key' => 'value'], $minutes);

cache(['key' => 'value'], now()->addSeconds(10));

{tip} 如果在测试中使用全局函数 cache ,你可以使用 Cache::shouldReceive 方法就像 测试 Facade。

缓存标记

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

写入被标记的缓存数据

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

Cache::tags(['people', 'artists'])->put('John', $john, $minutes);

Cache::tags(['people', 'authors'])->put('Anne', $anne, $minutes);

访问被标记的缓存数据

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

$john = Cache::tags(['people', 'artists'])->get('John');

$anne = Cache::tags(['people', 'authors'])->get('Anne');

移除被标记的缓存数据

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

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

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

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

增加自定义的缓存驱动

编写驱动

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

<?php

namespace App\Extensions;

use Illuminate\Contracts\Cache\Store;

class MongoStore implements Store
{
    public function get($key) {}
    public function many(array $keys);
    public function put($key, $value, $minutes) {}
    public function putMany(array $values, $minutes);
    public function increment($key, $value = 1) {}
    public function decrement($key, $value = 1) {}
    public function forever($key, $value) {}
    public function forget($key) {}
    public function flush() {}
    public function getPrefix() {}
}

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

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

{tip} 如果你不知道将缓存驱动代码放在哪,你可以在 app 目录下创建一个 Extensions 命名空间。但 Laravel 并没有硬性规定应用程序的结构,你可以根据自己的喜好自由组织你的应用程序。

注册驱动

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

<?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 中:

/**
 * 应用程序的事件侦听器映射。
 *
 * @var array
 */
protected $listen = [
    'Illuminate\Cache\Events\CacheHit' => [
        'App\Listeners\LogCacheHit',
    ],

    'Illuminate\Cache\Events\CacheMissed' => [
        'App\Listeners\LogCacheMissed',
    ],

    'Illuminate\Cache\Events\KeyForgotten' => [
        'App\Listeners\LogKeyForgotten',
    ],

    'Illuminate\Cache\Events\KeyWritten' => [
        'App\Listeners\LogKeyWritten',
    ],
];

点击查看所有 Laravel 中文文档 文章: https://www.codercto.com/courses/l/3.html

查看所有标签

The Nature of Code

The Nature of Code

Daniel Shiffman / The Nature of Code / 2012-12-13 / GBP 19.95

How can we capture the unpredictable evolutionary and emergent properties of nature in software? How can understanding the mathematical principles behind our physical world help us to create digital w......一起来看看 《The Nature of Code》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试