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中的登陆login
Jan 18 PHP
火车头采集器3.0采集图文教程
Mar 17 PHP
常用的php对象类型判断
Aug 27 PHP
PHP 引用文件技巧
Mar 02 PHP
从PHP的源码中深入了解stdClass类
Apr 18 PHP
PHP英文字母大小写转换函数小结
May 03 PHP
php实现SAE上使用storage上传与下载文件的方法
Jun 29 PHP
两款万能的php分页类
Nov 12 PHP
thinkPHP下ueditor的使用方法详解
Dec 26 PHP
Zend Framework分页类用法详解
Mar 22 PHP
PHP批量获取网页中所有固定种子链接的方法
Nov 18 PHP
THINKPHP在添加数据的时候获取主键id的值方法
Apr 03 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
PHP投票系统防刷票判断流程分析
2012/02/04 PHP
php设计模式之职责链模式实例分析【星际争霸游戏案例】
2020/03/27 PHP
[推荐]javascript 面向对象技术基础教程
2009/03/03 Javascript
Javascript类库的顶层对象名用户体验分析
2010/10/24 Javascript
让网页跳转到指定位置的jquery代码非书签
2013/09/06 Javascript
提高NodeJS中SSL服务的性能
2014/07/15 NodeJs
JS辨别访问浏览器判断是android还是ios系统
2014/08/19 Javascript
jQuery中height()方法用法实例
2014/12/24 Javascript
JS实现黑客帝国文字下落效果
2015/09/01 Javascript
jQuery密码强度检测插件passwordStrength用法实例分析
2015/10/30 Javascript
使用jQuery处理AJAX请求的基础学习教程
2016/05/10 Javascript
最全的Javascript编码规范(推荐)
2016/06/22 Javascript
yarn与npm的命令行小结
2016/10/20 Javascript
正则表达式替换html元素属性的方法
2016/11/26 Javascript
ajax与json 获取数据并在前台使用简单实例
2017/01/19 Javascript
使用socket.io实现简单聊天室案例
2018/01/02 Javascript
electron + vue项目实现打印小票功能及实现代码
2018/11/25 Javascript
jQuery实现鼠标移入显示蒙版效果
2020/01/11 jQuery
[00:34]拔城逐梦,热血永恒!2020(秋)完美世界城市挑战赛报名开启
2020/10/09 DOTA
使用python实现扫描端口示例
2014/03/29 Python
python中列表和元组的区别
2017/12/18 Python
win7+Python3.5下scrapy的安装方法
2018/07/31 Python
python实现简单的文字识别
2018/11/27 Python
Django如何防止定时任务并发浅析
2019/05/14 Python
如何在django中实现分页功能
2020/04/22 Python
python写文件时覆盖原来的实例方法
2020/07/22 Python
PyCharm 2020.2.2 x64 下载并安装的详细教程
2020/10/15 Python
高校毕业生登记表自我鉴定
2013/11/03 职场文书
纺织工程专业个人求职信范文
2014/01/27 职场文书
优秀教师工作感言
2014/02/16 职场文书
教研活动总结
2014/04/28 职场文书
表彰大会策划方案
2014/05/13 职场文书
演讲比赛的活动方案
2014/08/28 职场文书
2015年店长工作总结范文
2015/04/08 职场文书
朋友聚会祝酒词
2015/08/10 职场文书
python实现图片九宫格分割的示例
2021/04/25 Python