php redis 传递闭包,通过缓存构建高性能 Laravel 应用

通过缓存构建高性能 Laravel 应用

由 学院君 创建于3年前, 最后更新于 11个月前

版本号 #2

20678 views

9 likes

1 collects

c33ded3bfe6afc64dfb1b8bec54e42e1.png

配置

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

缓存配置文件还包含其他文档化的选项,确保仔细阅读这些选项。默认情况下,Laravel 被配置成使用文件缓存,这会将序列化数据和缓存对象存储到文件系统。对于大型应用,建议使用内存缓存如 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

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

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

缓存使用

获取缓存实例

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

不过,你还可以使用 Cache 门面,这也是我们在整个文档中使用的方式,Cache 门面提供了简单方便的方式对底层 Laravel 缓存契约实现进行访问:

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', 10);

从缓存中获取数据

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

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

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

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

$value = Cache::get('key', function() {

return DB::table(...)->get();

});

检查缓存项是否存在

has 方法用于判断缓存项是否存在,如果值为 null 或 false 该方法会返回 false:

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

//

}

数值增加/减少

increment 和 decrement 方法可用于调整缓存中的整型数值。这两个方法都可以接收第二个参数来指明缓存项数值增加和减少的数目:

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 门面上的 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');

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

从缓存中移除数据

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

Cache::forget('key');

还可以使用 flush 方法清除所有缓存:

Cache::flush();

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

缓存辅助函数

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

$value = cache('key');

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

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

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

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

缓存标签

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

存储被打上标签的缓存项

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

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

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

你可以给多个缓存项打上相同标签,这是没有数目限制的。

访问被打上标签的缓存项

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

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

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

移除被打上标签的数据项

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

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

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

相反,以下语句只移除被打上 authors 标签的语句,所以只有 Anne 会被移除而 John 不会:

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

添加自定义缓存驱动

编写驱动

要创建自定义的缓存驱动,首先需要实现 Illuminate\Contracts\Cache\Store 契约,所以,我们的 MongoDB 缓存实现看起来会像这样子:

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 连接来实现其中的每一个方法,想要看如何实现每个方法的示例,可以参考 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 数组:

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.php 的 driver 选项为自定义扩展名称即可。

缓存事件

要在每次缓存操作时执行代码,你可以监听缓存触发的事件,通常,你可以将这些缓存处理器代码放到 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',

],

];

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/529506.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

imclearboder matlab,Lucas

Lucas-Kanade跟踪算法是视觉跟踪中一个很经典的基于点的逐帧跟踪算法。起初这个算法是用来求解stero matching1的,后来经过Carlo Tomasi2和Jianbo Shi3等人的发展渐趋成熟。Jianbo Shi提出了一种筛选跟踪点特征的方法,使得特征的跟踪更可靠。Jean-Yves B…

php判断url参数为空,PHP检查url链接是否已经有参数的简单示例

这篇文章主要为大家详细介绍了PHP检查url链接是否已经有参数的简单示例,具有一定的参考价值,可以用来参考一下。感兴趣的小伙伴,下面一起跟随512笔记的小编小韵来看看吧!比如分页,因为有些链接已经有参数了&#xff0c…

java 读取 邮件 附件,JavaMail 中对附件下载的处理

在项目中使用 JavaMail 作为邮件核心库,但是一直遇到一个比较头疼的问题,当邮件中存在附件时,此封邮件加载速度很慢,最高时之后 80k/s.通过 log 打印看出,当获取附件时,获取一段之后等待一段时间在获取另一端.导致 io 开销过大,等待网络读取时间过长.相关日志如下:O24 FETCH 27…

matlab求勒让德多项式零点,有没有勒让德多项式导数 零点程序

求N1次勒让德多项式的m(m0,1,...)阶导数零点Matlab程序子程序:function xjp(N,alpha,beta)n1:N;a(1)(alphabeta2)/2;b(1)(beta-alpha)/2;a([2:N1])(2*nalphabeta1).*(2*nalphabeta2)./(2*(n1).*(nalphabeta1));b([2:N1])(alpha*alpha-beta*beta)*(2*nalphabeta1)./(…

js_long.php,protobuf.js 与 Long.js的使用详解

这次给大家带来protobuf.js 与 Long.js的使用详解,是急用protobuf.js 与 Long.js的注意事项有哪些,下面就是实战案例,一起来看一下。protobuf.js的结构和webpack的加载之后的结构很相似。这样的模块化组合是个不错的结构方式。1个是适应了不同…

微分进化算法解决函数优化问题的matlab代码,Matlab微分进化算法及优化函数测试...

微分进化(Difference Evolution,DE)算法是一种优化算法,据称其比GA(遗传算法)等更为优秀。借鉴网上实现的DE算法,用Matlab实现了对若干函数优化问题的解法,代码如下:function [] de_testclear all;close all;clc;%解&…

Oracle中获取文件中的数据,操作oracle中的数据文件

收藏于http://dev.yesky.com/296/8090796.shtmlOracle数据库中管理表空间和数据文件数据库的三大组成部分:数据文件,控制文件,Redo日志。表空间分为系统表空间和非系统表空间。SYSTEM表空间是最基本的,必须的,Oracle建议你为用户数…

oracle 存储过程设置回滚点,(转)oracle 存储过程事宜使用断点回滚 -savepoint

学习存储过程中使用断点回滚事务时,发现目前网络上存在一个问题,那就是使用断点回滚后,都忘记了一个很重要的事情,提交事务。虽然使用了断点回滚,但是断点回滚不像rollBack或commit一样结束当前事务,而使用…

php tp5清空数据表并主键,tp5数据库——更新数据

更新数据更新数据表中的数据Db::table(think_user)->where(id, 1)->update([name > thinkphp]);如果数据中包含主键,可以直接使用:Db::table(think_user)->update([name > thinkphp,id>1]);update 方法返回影响数据的条数,…

oracle几个网络,ORACLE网络的几个重点概念

数据库名(DB_NAME)、数据库实例名(INSTANCE_NAME)、操作系统环境变量ORACLE_SID、数据库服务名 (SERVICE_NAME)、数据库域名(DB_DOMAIN)以及全局数据库名(GLOBAL_DB_NAME)是几个使用Oracle数据库容易混 淆的概念。1、数据库名与实例名数据库名(DB_NAME):是区分数据的…

oracle每季度补丁,Oracle 2020 年第四季度补丁发布

半个月前,也就是 10 月 20 日, Oracle 发布了今年最后一次补丁更新,那么很多人都想打最新的 PSU,理由是有被扫到各种漏洞,有的扫描工具着实太坑,这里就不用说了,前几天看到盖总发布的文章2020年…

php flash上传进度条,PHP_PHP+FLASH实现上传文件进度条相关文件 下载,PHP之所以很难实现上传进度条 - phpStudy...

PHPFLASH实现上传文件进度条相关文件 下载PHP之所以很难实现上传进度条是因为在我们上传文件到服务器的时候,要等到文件全部送到服务器之后,才执行相应的php文件。在这之前,文件数据保存在一个临时文件里面,而php无法获得这个文件…

oracle截取时间函数6,SQL 取日期部分函数

convert(varchar(10),getdate(),120)这个函数就可以得到日期部分了,我觉得还是比较方便的,我觉得SQL在日期方面,没有ORACLE函数坐的好。。Sql Server中的日期与时间函数1. 当前系统日期、时间select getdate()2. dateadd 在向指定日期加上一…

oracle 找不到程序,Oracle 找不到监听程序

Oracle服务器文件 app\Administrator\product\11.2.0\dbhome_1\NETWORK\ADMIN\listener.oraSID_LIST_LISTENER (SID_LIST (SID_DESC (SID_NAME CLRExtProc)(ORACLE_HOME D:\app\Administrator\product\11.2.0\dbhome_1)(PROGRAM extproc)(ENVS "EXTPROC_DLLSONLY:D:\…

oracle中的存储过程教程,oracle 存储过程

-- 查看系统定时任务SELECT * FROM DBA_JOBS-- 新建定时任务DECLAREjobno NUMBER;BEGINSYS.DBMS_JOB.SUBMIT(JOB > jobno, /*自动生成JOB_ID*/WHAT > qmcb_ls_data;, /*需要执行的存储过程名称或SQL语句*/NEXT_DATE > SYSDATE, /*初次执行时间-立即执行*/INTERVAL >…

Oracle segment啥意思,关于oracle数据库段segment的小结

段(segment)是一种在数据库中消耗物理存储空间的任何实体(一个段可能存在于多个数据文件中,因为物理的数据文件是组成逻辑表空间的基本物理存储单位)今天碰到一个高水位问题:一个分区表,删除某个分区中的一些数据后,表空间并没有回…

Linux在文件第一行添加字符,使用shell命令给文件中每一行的前面、后面、指定列添加字符...

shell给一个文件中的每一行开头插入字符的方法:awk {print "X"$0} fileNameshell给一个文件中的每一行结尾插入字符的方法:awk {print $0"X"} fileNameshell给一个文件中的每一行的指定列插入字符的方法:awk $O$O" …

路由器 刷 linux系统版本,在Linux下用tftp刷写路由器固件

(以Buffalo WHR-G300N V2路由器为例)以发行版Ubuntu为例(如果你在Windows下,可下载Ubuntu的ISO文件,再用wubi安装Ubuntu,可免去重新分区的麻烦),下载Buffalo WHR-G300N V2路由器的FTP版固件文件,放到Ubuntu的/home目录…

linux没有etho网卡,关于怎么解决CENTOS7没有ETH0网卡这个问题

CentOS7系统安装完毕之后,输入ifconfig命令发现没有eth0,不符合我们的习惯。而且也无法远程ssh连接。1.进入目录/etc/sysconfig/network-scripts/2.将文件ifcfg-ens33重命名为ifcfg-eth0;(注意:修改需要切换至root用户)3.编辑ifcfg-eth0使用命令&#xf…

linux添加物理卷编辑文件夹,Red hat Linux下的逻辑卷管理器LVM-上

【IT168 专稿】Red hat 下的LVM 上 LVM是Logical Volume Manager(逻辑卷管理器)的简写,它为主机提供了更高层次的磁盘存储管理能力。LVM可以帮助系统管理员为应用与用户方便地分配存储空间。在LVM管理下的逻辑卷可以按需改变大小或添加移除。另外,LVM可以…