laravel 基础教程 —— 缓存

缓存

配置

Laravel 对多种缓存系统提供了统一的 API。缓存的配置文件存放在 config/cache.php。你可以在这个文件中指定整个应用默认使用何种缓存驱动。Laravel 支持当前主流的缓存系统如 Memcached 和 Redis。

缓存的配置文件也包含了一些额外的配置选项,这些选项在文件中都有文档注释,你应该确保自己已经读了这些选项注释。默认的,Laravel 配置使用 file 缓存驱动,该驱动会在文件系统中存储序列化的缓存对象。对于大型应用,建议使用内存级的缓存,如 Memcached 或者 APC。你甚至可以在 laravel 中配置多种缓存配置到相同的驱动。

缓存先决条件

数据库

当使用 database 缓存驱动时,你需要建立一个表来包含这些缓存项。你可以根据下面的 Schema 定义来建立表文件:

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

你也可以通过使用 php artisan cache:table Artisan 命令来生成正确的缓存表结构迁移。

Memcached

使用 Memcached 缓存需要安装 Memcached PECL package

默认的配置基于 Memcached::addServer 使用 TCP/IP:

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

你也可以使用 UNIX socket 路径来设置 host。如果你这么做,你需要设置 port0:

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

Redis

在你使用 Redis 缓存之前,你需要先通过 Composer 安装 predis/predis
关于更多的 Redis 配置信息,你可以参考 Laravel documentation page

缓存使用

获取缓存实例

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

事实上,你也可以使用 Cache 假面,在这篇文档中,我们都是使用 Cache 假面进行举例。Cache 假面提供了一种方便简洁的方式来访问 Laravel 底层缓存契约的实现。

例如,让我们引入 Cache 假面到控制器:

<?php

namespace App\Http\Controllers;

use Cache;

class UserController extends Controller 
{
  /**
   * Show a list of all users of the application.
   *
   * @return Response
   */
   public function index()
   {
     $value = Cache::get('key');

     //
   }
}

访问多种缓存存储

你可以通过 Cache 假面的 store 方法来访问多种缓存存储。传递到 store 方法的 key 应该与你的 cache 配置文件中的 stores 配置项的列表之一相匹配:

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

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

获取缓存项

你可以通过使用 Cache 假面的 get 方法来从缓存中获取相关项的值。如果该项在缓存中并不存在,则返回 null 。如果你需要,你也可以传递第二个参数到 get 方法,这个参数所传递的值会在缓存中项不存在时被返回:

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

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

你甚至可以传递 Closure 作为默认值。如果缓存的项不存在,Closure 所返回的值将被做为默认值。传递闭包的方式可以使你从数据库或者其他外部服务中延迟获取默认值:

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

检查项是否存在

你可以使用 has 方法来检查缓存中是否存在该项:

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(); 
});

如果缓存中没有检索到该项,传递到 remeber 方法中的闭包将会被执行并且其执行结果将会在缓存中进行替换。

你也可以合并 rememberforever 方法:

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

检索并删除

如果你需要检索一个项目,并在检索到的同时从缓存中删除该项,你可以使用 pull 方法。就像 get 方法一样,如果未检索到该项,将会返回 null :

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

存储项目到缓存

你可以使用 Cache 假面的 put 方法来存储项目到缓存中。当你存储一个项到缓存中时,你需要指定一个该项需要被缓存的分钟值:

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

除了传递一个数值作为缓存过期的分钟值,你也可以通过传递一个 PHP DateTime 实例来设置缓存的失效时间:

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

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

add 方法只会在相应的项在缓存中不存在时才会被添加进缓存。该方法会在项目被添加到缓存后返回 true。否则返回 false

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

forever 方法可以用来将项目永久的添加进缓存。该值只有手动的使用 forget 方法才能被移除:

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

从缓存中移除项目

你可以使用 Cache 假面的 forget 方法来从缓存中移除某项:

Cache::forget('key');

你可以使用 flush 方法来擦除所有的缓存:

Cache::flush();

擦除缓存并不会根据前缀来进行智能擦除,它会移除所有的缓存。所以如果你的应用和其他的应用共享缓存,你应该谨慎的使用该方法。

缓存标签

注意: 缓存标签并不支持 file 或者 database 缓存驱动。另外,对于将多种标签标记为永久存储的驱动,性能最好的是能够提供自动清除过期记录的驱动,比如 memcached

存储标记了的项目到缓存

缓存标签允许你将相关的项目进行关联标记。并且允许一次性清除所有给定标签的缓存项。你可以通过有序的标签数组来访问被标记的缓存项目。比如,让我们访问被标记的项目并使用 put 方法来设置缓存值:

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

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

事实上,你并没有被限制只使用 put 方法。你可以在标签中使用任意的缓存存储方法。

访问被标记的缓存项

为了访问被标记了的缓存项,你需要传递相应的有序列表到 tags 方法:

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

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

你可以一次性的擦除分配的标记或者标记列表中的所有项。比如,你可以使用 flush 方法来删除所有的 peopleauthors 标签和两者组成的有序列标签里的所有缓存项。所以,AnneJohn 都会被从缓存中移除:

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

下面的语句将会作为上面语句的对照,将只会从缓存中删除 authors 标签的项目,所以 Anne 会被删除,而 John 被保留:

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

添加自定义的缓存驱动

为了在自定义的缓存驱动中继承 laravel 的缓存。我们需要使用 Cache 假面的 extend 方法,该方法被用来绑定自定义缓存到底层管理中。通常这些都是在服务提供者中完成。

比如,注册一个新的缓存驱动并命名为 'mongo':

<?php

namespace App\Providers;

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

class CacheServiceProvider extends ServiceProvider
{
  /**
   * Perform post-registration booting of services.
   *
   * @return void
   */
   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 实例,这个实例是 laravel 中的服务容器的实例。

Cache::extend 方法的调用应该在 App\Providers\AppServiceProviderboot 方法中完成。或者你可以创建自己的服务提供者来存储这个扩展。但是不要忘记在 config/app.php 文件中进行注册。

为了创建我们自己的缓存驱动,我们首先需要实现 Illuminate\Constracts\Cache\Store 契约的接口。所以,我们的 MongoDB 缓存实现应该看起来像这样:

<?php

namespace App\Extensions;

class MongoStore implements \Illuminate\Contracts\Cache\Store
{
  public function get($key) {}
  public function put($key, $value, $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 连接来实现这些方法。一旦我们的实现完成,我们就可以完成自己的缓存驱动的注册:

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

然后在 config/cache.php 配置文件中更新驱动为的名称 driver 为你的扩展的名称。

如果你在为自定义的缓存文件应该存放在哪里而疑惑,你可以考虑将其发布到 Packagist!或者,你可以在 app 目录中创建一个 Extensions 命名空间。事实上,你应该谨记,laravel 并不死板的限制你的目录结构,你应该可以根据自己的习惯自由的管理你的应用目录结构。

事件

如果你想在任何缓存被操作时执行额外的代码,你可能需要监听缓存的触发事件。通常的你应该存放这些事件监听器到你的 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',
  ],
 ];
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容

  • 1、配置 Laravel 为不同的缓存系统提供了统一的 API。缓存配置位于 config/cache.php。在...
    layjoy阅读 949评论 0 1
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,600评论 18 139
  • 原文链接 必备品 文档:Documentation API:API Reference 视频:Laracasts ...
    layjoy阅读 8,603评论 0 121
  • 测试 简介 测试是 Laravel 构建的核心理念。事实上,Laravel 开箱即用的支持 PHPUnit 测试,...
    Dearmadman阅读 8,058评论 2 28
  • 简介 laravel 使实施认证的变得非常简单,事实上,它提供了非常全面的配置项以适应应用的业务。认证的配置文件存...
    Dearmadman阅读 6,112评论 2 13