[ Laravel 5.8 文档 ] 进阶系列 —— 缓存

栏目: 数据库 · 发布时间: 5年前

内容简介:Laravel 为不同的缓存系统提供了统一的 API。缓存配置位于缓存配置文件还包含其他文档化的选项,确保仔细阅读这些选项。默认情况下,Laravel 被配置成使用文件缓存(使用

配置

Laravel 为不同的缓存系统提供了统一的 API。缓存配置位于 config/cache.php 。在该文件中你可以指定在应用中默认使用哪个缓存驱动。Laravel 开箱支持主流的缓存后端如 MemcachedRedis 等。

缓存配置文件还包含其他文档化的选项,确保仔细阅读这些选项。默认情况下,Laravel 被配置成使用文件缓存( file 驱动),这会将序列化数据和缓存对象存储到文件系统。对于大型应用,建议使用内存缓存如 Memcached 或 APC,你甚至可以为同一驱动配置多个缓存配置。

驱动预备知识

数据库

使用 database 缓存驱动时,你需要设置一张表存储缓存项。下面是该表的 Schema 声明:

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

注:你还可以使用 Artisan 命令 php artisan cache:table 通过相应的 schema 生成迁移。

Memcached

使用 Memcached 缓存要求安装了 Memcached PECL 包 ,即 PHP Memcached 扩展。你可以在配置文件 config/cache.php 中列出所有 Memcached 服务器:

'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

使用 LaravelRedis 缓存之前,你需要通过 Composer 安装 predis/predis 包(~1.0)。

想要了解更多关于 Redis 的配置,查看 Larave 的Redis 文档。

缓存使用

获取缓存实例

Illuminate\Contracts\Cache\FactoryIlluminate\Contracts\Cache\Repository 契约提供了访问 Laravel 缓存服务的方法。 Factory 契约提供了所有访问应用定义的缓存驱动的方法。 Repository 契约通常是应用中 cache 配置文件中指定的默认缓存驱动的一个实现。

不过,你还可以使用 Cache 门面,这也是我们在整个文档中使用的方式, Cache 门面提供了简单方便的方式对底层 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 门面,你可以使用 store 方法访问不同的缓存存储器,传入 store 方法的键就是 cache 配置文件中 stores 配置数组里列出的相应的存储器:

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

从缓存中获取数据

Cache 门面的 get 方法用于从缓存中获取缓存项,如果缓存项不存在,返回 null 。如果需要的话你可以传递第二个参数到 get 方法指定缓存项不存在时返回的自定义默认值:

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

你甚至可以传递一个闭包作为默认值,如果缓存项不存在的话闭包的结果将会被返回。传递闭包允许你可以从数据库或其它外部服务获取默认值:

$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', $seconds, 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 门面上的 put 方法在缓存中存储数据。当你在缓存中存储数据的时候,需要指定数据被缓存的时间(秒数):

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

如果没有传递缓存时间到 put 方法,则缓存项永久有效:

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

除了传递缓存项失效时间,你还可以传递一个代表缓存项有效时间的 PHP Datetime 实例:

$expiresAt = Carbon::now()->addMinutes(10);
Cache::put('key', 'value', $expiresAt);

缓存不存在时存储数据

add 方法只会在缓存项不存在的情况下添加数据到缓存,如果数据被成功添加到缓存返回 true ,否则,返回 false

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

永久存储数据

forever 方法用于持久化存储数据到缓存,这些值必须通过 forget 方法手动从缓存中移除:

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

注:如果你使用的是 Memcached 驱动,当缓存数据达到上限后永久存储的数据就会被移除。

从缓存中移除数据

你可以使用 Cache 门面上的 forget 方法从缓存中移除缓存项数据:

Cache::forget('key');

还可以通过设置缓存有效期为 0 或负数来移除缓存项:

Cache::put('key', 'value', 0);

Cache::put('key', 'value', -5);

如果要清除所有缓存,可以通过 flush 方法:

Cache::flush();

注:清除缓存并不管什么缓存键前缀,而是从缓存系统中移除所有数据,所以在使用这个方法时如果其他应用与本应用有共享缓存时需要格外注意。

原子锁

注:要使用这个功能,应用必须使用 memcacheddynamodbredis 缓存驱动作为应用默认的缓存驱动,此外,所有服务器必须和同一台中央缓存服务器进行通信。

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

if (Cache::lock('foo', 10)->get()) {
    // Lock acquired for 10 seconds...

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

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

Cache::lock('foo')->get(function () {
    // Lock acquired indefinitely and automatically released...
});

如果锁在你请求的时候无效,可以告知 Laravel 等待直到锁有效。如果锁在指定限制时间内无法获取,会抛出 Illuminate\Contracts\Cache\LockTimeoutException 异常:

use Illuminate\Contracts\Cache\LockTimeoutException;

$lock = Cache::lock('foo', 10);

try {
    $lock->block(5);

    // Lock acquired after waiting maximum of 5 seconds...
} catch (LockTimeoutException $e) {
    // Unable to acquire lock...
} finally {
    optional($lock)->release();
}

Cache::lock('foo', 10)->block(5, function () {
    // Lock acquired after waiting maximum of 5 seconds...
});

管理跨进程的锁

有时候,你可能想要在一个进程中获取锁,在另一个进程中释放锁。例如,你可以在 Web 请求期间获取锁,然后在该请求触发的某个队列任务最后释放这把锁。在这种场景下,你应该传递锁的域「」

缓存辅助函数

除了使用 Cache 门面或缓存契约,还可以使用全局的 cache 函数来通过缓存获取和存储数据。当带有一个字符串参数的 cache 函数被调用时,会返回给定键对应的缓存值(取值):

$value = cache('key');

如果你提供了键值对数组和一个过期时间给该函数,则会在指定的有效期内存储缓存值(存储):

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

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

cache 函数不带任何参数被调用时会返回 Illuminate\Contracts\Cache\Factory 实现的实例,从而允许你调用其它缓存方法:

cache()->remember('users', $seconds, function () {
    return DB::table('users')->get();
});

测试调用 cache 函数时,可以像测试门面一样使用 Cache::shouldReceive 方法。

缓存标签

注:缓存标签目前不支持 filedatabase 缓存驱动,此外,当使用多标签的缓存被设置为永久存储时,使用 memcached 驱动的缓存有着最佳性能表现,因为 Memcached 会自动清除陈旧记录。

存储被打上标签的缓存项

缓存标签允许你给相关缓存项打上同一个标签以便于后续清除这些缓存值,被打上标签的缓存可以通过传递一个被 排序 的标签数组来访问。例如,我们可以通过以下方式在添加缓存的时候设置标签:

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

访问被打上标签的缓存项

要获取被打上标签的缓存项,传递同样的有序标签数组到 tags 方法然后使用你想要获取的key来调用 get 方法:

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

移除被打上标签的数据项

你可以同时清除被打上同一标签/标签列表的所有缓存项,例如,以下语句会移除被打上 peopleauthors 标签的所有缓存:

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

这样,上面设置的 AnneJohn 缓存项都会从缓存中移除。

相反,以下语句只移除被打上 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, $seconds) {}
    public function putMany(array $values, $seconds);
    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 连接来实现其中的每一个方法,想要看如何实现每个方法的示例,可以参考 Laravel 底层源码 Illuminate\Cache\MemcachedStore ,实现完成后,我们就可以完成自定义驱动注册:

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

注:如果你在担心将自定义缓存驱动代码放到哪,可以在 app 目录下创建一个 Extensions 命名空间。不过,记住 Laravel 并没有一个严格的应用目录结构,你可以基于你的需要自由的组织目录结构。

注册驱动

要通过 Laravel 注册自定义的缓存驱动,可以使用 Cache 门面上的 extend 方法。对 Cache::extend 的调用可以在 Laravel 自带的 App\Providers\AppServiceProvider 提供的 boot 方法中完成,或者,你也可以创建自己的服务提供者来存放扩展——只是别忘了在配置文件 config/app.php 中注册服务提供者到 providers 数组:

<?php

namespace App\Providers;

use App\Extensions\MongoStore;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\ServiceProvider;

class CacheServiceProvider extends ServiceProvider
{
    /**
     * Perform post-registration booting of services.
     *
     * @return void
     * @translator laravelacademy.org
     */
    public function boot()
    {
        Cache::extend('mongo', function($app) {
            return Cache::repository(new MongoStore);
        });
    }

    /**
     * Register bindings in the container.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

传递给 extend 方法的第一个参数是驱动名称。该值对应配置文件 config/cache.php 中的 driver 选项。第二个参数是返回 Illuminate\Cache\Repository 实例的闭包。该闭包中被传入一个 $app 实例,也就是服务容器的一个实例。

扩展被注册后,只需简单更新配置文件 config/cache.phpdriver 选项为自定义扩展名称即可。

缓存事件

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

/**
 * The event listener mappings for the application.
 *
 * @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',
    ],
];

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Java多线程编程实战指南(设计模式篇)

Java多线程编程实战指南(设计模式篇)

黄文海 / 电子工业出版社 / 2015-10 / 59.00

随着CPU 多核时代的到来,多线程编程在充分利用计算资源、提高软件服务质量方面扮演了越来越重要的角色。而 解决多线程编程中频繁出现的普遍问题可以借鉴设计模式所提供的现成解决方案。然而,多线程编程相关的设计模式书籍多采用C++作为描述语言,且书中所举的例子多与应用开发人员的实际工作相去甚远。《Java多线程编程实战指南(设计模式篇)》采用Java(JDK1.6)语言和UML 为描述语言,并结合作者多......一起来看看 《Java多线程编程实战指南(设计模式篇)》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

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

HTML 编码/解码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码