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环境搭建最新方法
Sep 05 PHP
php学习之 数组声明
Jun 09 PHP
php 阴历-农历-转换类代码
Jan 16 PHP
php类中的各种拦截器用法分析
Nov 03 PHP
PHP生成不重复随机数的方法汇总
Nov 19 PHP
详解PHP实现执行定时任务
Dec 21 PHP
微信支付PHP SDK ―― 公众号支付代码详解
Sep 13 PHP
利用Laravel事件系统如何实现登录日志的记录详解
May 20 PHP
利用PHP获取访客IP、地区位置、浏览器及来源页面等信息
Jun 27 PHP
基于laravel where的高级使用方法
Oct 10 PHP
使用laravel根据用户类型来显示或隐藏字段
Oct 17 PHP
laravel model 两表联查示例
Oct 24 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
thinkphp路由规则使用示例详解和伪静态功能实现(apache重写)
2014/02/24 PHP
PHP获取本周第一天和最后一天示例代码
2014/02/24 PHP
PHP中isset()和unset()函数的用法小结
2014/03/11 PHP
Mac环境下php操作mysql数据库的方法分享
2015/05/11 PHP
PHP中md5()函数的用法讲解
2019/03/30 PHP
JavaScript Date对象使用总结
2009/05/14 Javascript
javascript实现dom动态创建省市纵向列表菜单的方法
2015/05/14 Javascript
Jquery实现遮罩层的方法
2015/06/08 Javascript
JavaScript Array对象详解
2016/03/01 Javascript
js实现select二级联动下拉菜单
2020/04/17 Javascript
bootstrap-wysiwyg结合ajax实现图片上传实时刷新功能
2016/05/27 Javascript
Javascript中的迭代、归并方法详解
2016/06/14 Javascript
jQuery插件easyUI实现通过JS显示Dialog的方法
2016/09/16 Javascript
浅谈jQuery this和$(this)的区别及获取$(this)子元素对象的方法
2016/11/29 Javascript
node.js请求HTTPS报错:UNABLE_TO_VERIFY_LEAF_SIGNATURE\的解决方法
2016/12/18 Javascript
JS+HTML5 Canvas实现简单的写字板功能示例
2018/08/30 Javascript
微信小程序实现笑脸评分功能
2018/11/03 Javascript
axios+Vue实现上传文件显示进度功能
2019/04/14 Javascript
基于aotu.js实现微信自动添加通讯录中的联系人功能
2020/05/28 Javascript
[04:04]显微镜下的DOTA2第六期——电影级别的华丽团战
2014/06/20 DOTA
[01:02:02]DOTA2上海特级锦标赛A组败者赛 EHOME VS CDEC第二局
2016/02/25 DOTA
Python开发编码规范
2006/09/08 Python
使用grappelli为django admin后台添加模板
2014/11/18 Python
python使用socket远程连接错误处理方法
2015/04/29 Python
Python字符串格式化
2015/06/15 Python
python获取文件扩展名的方法
2015/07/06 Python
Python获取暗黑破坏神3战网前1000命位玩家的英雄技能统计
2016/07/04 Python
神经网络理论基础及Python实现详解
2017/12/15 Python
联想台湾官网:Lenovo TW
2018/05/09 全球购物
阿迪达斯香港官网:adidas香港
2019/11/09 全球购物
试用期员工考核制度
2014/01/22 职场文书
翻译学院毕业生自荐书
2014/02/02 职场文书
后勤主管岗位职责
2014/03/01 职场文书
家长通知书教师评语
2014/04/17 职场文书
简短清晨问候语
2015/11/10 职场文书
Python 用户输入和while循环的操作
2021/05/23 Python