php使用redis的几种常见操作方式和用法示例


Posted in PHP onFebruary 20, 2020

本文实例讲述了php使用redis的几种常见操作方式和用法。分享给大家供大家参考,具体如下:

一、简单的字符串缓存

比如针对一些sql查询较慢,更新不频繁的数据进行缓存。

<?php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379, 60);
$sql = 'select * from tb_order order by id desc limit 10';
//伪代码,从数据库中获取数据
$data = $db->query($sql);
$data = json_encode($data, JSON_UNESCAPED_UNICODE);
$key = md5($sql);
//缓存数据
$redis->set($key, $value, 60);
//获取数据
$data = $redis->get($key);
print_r(json_decode($data, true));

二、通过列表模拟简单队列

比如我们需要批量的发送邮件,可以把发送邮件的任务存入队列中,然后启多个php脚本从队列中读取任务去发送邮件。

也可以用来处理商品秒杀,用户点击抢购时,把一个个的用户抢购任务放入队列中,串行化处理,判断队列数量,防止超卖的发生。

<?php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379, 60);
//循环的把发送1000条邮件任务插入队列
for ($ix = 0; $ix < 1000; $ix++) {
  $redis->lPush('send_email_queue', json_encode([
    'id' => $ix,
    'send' => 'xxx@qq.com',
    'receive' => 'yyy@qq.com',
    'title' => 'xxx',
    'body' => 'xxx',
  ]));
}
sleep(3);
//从队列中取任务,执行任务
while ($count = $redis->lLen('send_email_queue')) {
  echo "当前任务队列数 {$count} <br>";
  $task = $redis->rpop('send_email_queue');
  $task = json_decode($task, true);
  //伪代码,发送邮件
  $mailer->send($task['send'], $task['receive'], $task['title'], $task['body']);
  echo "任务 {$task['id']} 邮件发送成功<br>";
}

三、通过watch + multi 来实现乐观锁

乐观锁,顾名思义,乐观的认为数据不会被修改,只有当更新时才去判断数据是否被修改过,通常用版本号或时间戳来实现。

redis中通过watch和multi来实现,watch会监视给定的key是否发生更改,当exec的时候如果监视的key发生过改变,则整个事务会失败。

当然我们可以调用多次watch监视多个key。

<?php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379, 60);
//设置商品的库存数为100
$redis->set('goods_stock_nums', 100);
//监视该key
$redis->watch('goods_stock_nums');
//开启事务
$redis->multi();
//修改库存数
$redis->decr('goods_stock_nums');
//提交事务,如果在此期间有其他请求修改了该key,那么事务会失败
if ($redis->exec()) {
  echo '抢购成功';
} else {
  echo '数据错误,请重新再试';
}

四、使用 set 来实现悲观锁

悲观锁,顾名思义,悲观的认为数据总是会被修改,所以在操作前都会先加上锁,操作完后,再释放锁。

<?php
function getRedis()
{
  $redis = new Redis();
  $redis->connect('127.0.0.1', 6379, 60);
  return $redis;
}
function lock($key, $random)
{
  $redis = getRedis();
  return $redis->set($key, $random, ['nx', 'ex' => 3]);
}
function unlock($key, $random)
{
  $redis = getRedis();
  //使用lua脚本保证原子性
  $script = 'if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end';
  return $redis->eval($script, [$key, $random], 1);
}
function decrGoodsStockNums()
{
  $redis = getRedis();
  //获取商品库存数
  $ret = $redis->get('goods_stock_nums');
  if ($ret === false) {
    return false;
  }
  if ($ret <= 0) {
    return false;
  }
  $random = mt_rand();
  //先获取锁
  if (lock('goods_stock_nums_lock', $random)) {
    //修改库存数
    $redis->decr('goods_stock_nums');
    //释放锁
    unlock('goods_stock_nums_lock', $random);
    return true;
  } else {
    usleep(100);
    decrGoodsStockNums();
  }
}
decrGoodsStockNums();

五、使用 publish + subscribe 完成发布和订阅

发布代码:

<?php
$redis = new Redis();
$redis->pconnect('127.0.0.1', 6379);
$ix = 0;
//发布内容
while (true) {
  $redis->publish('news', json_encode([
    'title' => '我是新闻标题' . $ix,
    'content' => '我是新闻内容' . $ix,
    'time' => date('Y-m-d H:i:s'),
  ]));
  $ix++;
  sleep(1);
}

订阅代码:

<?php
$redis = new Redis();
$redis->pconnect('127.0.0.1', 6379);
//订阅内容
$redis->subscribe(['news'], function ($redis, $channel, $msg) {
  $msg = json_decode($msg, true);
  echo "标题: {$msg['title']} 内容: {$msg['content']} 时间: {$msg['time']} <br>";
});

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
PHP的FTP学习(一)
Oct 09 PHP
Ajax+PHP 边学边练 之二 实例
Nov 24 PHP
如何在smarty中增加类似foreach的功能自动加载数据
Jun 26 PHP
PHP对表单提交特殊字符的过滤和处理方法汇总
Feb 18 PHP
PHP程序员基本要求和必备技能
May 09 PHP
Thinkphp搜索时首页分页和搜索页保持条件分页的方法
Dec 05 PHP
PHP进程同步代码实例
Feb 12 PHP
php转换颜色为其反色的方法
Apr 27 PHP
PHP中的session安全吗?
Jan 22 PHP
ThinkPHP表单令牌错误的相关解决方法分析
May 20 PHP
功能强大的php分页函数
Jul 20 PHP
阿里云Win2016安装Apache和PHP环境图文教程
Mar 11 PHP
PHP使用openssl扩展实现加解密方法示例
Feb 20 #PHP
php使用redis的有序集合zset实现延迟队列应用示例
Feb 20 #PHP
解决windows上php xdebug 无法调试的问题
Feb 19 #PHP
laravel框架路由分组,中间件,命名空间,子域名,路由前缀实例分析
Feb 18 #PHP
laravel框架select2多选插件初始化默认选中项操作示例
Feb 18 #PHP
laravel框架使用FormRequest进行表单验证,验证异常返回JSON操作示例
Feb 18 #PHP
PHP For循环字母A-Z当超过26个字母时输出AA,AB,AC
Feb 16 #PHP
You might like
建站常用13种PHP开源CMS比较
2009/08/23 PHP
浅谈PHP正则表达式中修饰符/i, /is, /s, /isU
2014/10/21 PHP
PHP+swoole实现简单多人在线聊天群发
2016/01/19 PHP
Gambit vs CL BO3 第一场 2.13
2021/03/10 DOTA
IE event.srcElement和FF event.target 功能比较
2010/03/01 Javascript
js如何设置在iframe框架中指定div不显示
2013/12/04 Javascript
javascript的动态加载、缓存、更新以及复用(一)
2014/06/09 Javascript
JS函数this的用法实例分析
2015/02/05 Javascript
深入理解JavaScript系列(38):设计模式之职责链模式详解
2015/03/04 Javascript
Javascript中的arguments与重载介绍
2015/03/15 Javascript
JavaScript获取网页表单action属性的方法
2015/04/02 Javascript
利用js实现禁止复制文本信息
2015/06/03 Javascript
javascript实现网页子页面遍历回调的方法(涉及 window.frames、递归函数、函数上下文)
2015/07/27 Javascript
Bootstrap每天必学之前端开发框架
2015/11/19 Javascript
基于Vuejs实现购物车功能
2016/08/02 Javascript
jQuery通过ajax快速批量提交表单数据
2016/10/25 Javascript
jQuery.ajax实现根据不同的Content-Type做出不同的响应
2016/11/03 Javascript
Thinkphp5微信小程序获取用户信息接口的实例详解
2017/09/26 Javascript
bootstrap时间插件daterangepicker使用详解
2017/10/19 Javascript
基于Vue2.X的路由和钩子函数详解
2018/02/09 Javascript
jQuery事件blur()方法的使用实例讲解
2019/03/30 jQuery
150行代码带你实现微信小程序中的数据侦听
2019/05/17 Javascript
vue数据更新UI不刷新显示的解决办法
2020/08/06 Javascript
python创建线程示例
2014/05/06 Python
低版本中Python除法运算小技巧
2015/04/05 Python
Python实现统计单词出现的个数
2015/05/28 Python
在Python的Django框架中为代码添加注释的方法
2015/07/16 Python
利用Python读取txt文档的方法讲解
2018/06/23 Python
基于Python实现签到脚本过程解析
2019/10/25 Python
如何用Matplotlib 画三维图的示例代码
2020/07/28 Python
ZWILLING双立人英国网上商店:德国刀具锅具厨具品牌
2018/05/15 全球购物
来自南加州灵感的工作和娱乐服装:TravisMathew
2019/05/01 全球购物
意大利男装网店:Vrients
2019/05/02 全球购物
人力资源本科毕业生求职信
2014/06/04 职场文书
html5中sharedWorker实现多页面通信的示例代码
2021/05/07 Javascript
mysql创建存储过程及函数详解
2021/12/04 MySQL