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 相关文章推荐
将数组写入txt文件 var_export
Apr 21 PHP
php表单转换textarea换行符的方法
Sep 10 PHP
基于php无限分类的深入理解
Jun 02 PHP
深入php list()函数的详解
Jun 05 PHP
解析php中heredoc的使用方法
Jun 17 PHP
Linux下手动编译安装PHP扩展的例子分享
Jul 15 PHP
PHP中应该避免使用同名变量(拆分临时变量)
Apr 03 PHP
php使用Jpgraph绘制柱形图的方法
Jun 10 PHP
php文件类型MIME对照表(比较全)
Oct 07 PHP
PHP模拟http请求的方法详解
Nov 09 PHP
yii2多图上传组件的使用教程
May 10 PHP
PHP连接MySQL数据库操作代码实例解析
Jul 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
第1次亲密接触PHP5(2)
2006/10/09 PHP
PHP的栏目导航程序
2006/10/09 PHP
PHP在字符断点处截断文字的实现代码
2011/04/21 PHP
深入mysql_fetch_row()与mysql_fetch_array()的区别详解
2013/06/05 PHP
php下foreach提示Warning:Invalid argument supplied for foreach()的解决方法
2014/11/11 PHP
PHP跨平台获取服务器IP地址自定义函数分享
2014/12/29 PHP
php构造函数的继承方法
2015/02/09 PHP
PHP在linux上执行外部命令的方法
2017/02/06 PHP
经典的解除许多网站无法复制文字的绝招
2006/12/31 Javascript
Sample script that deletes a SQL Server database
2007/06/16 Javascript
javascript fullscreen全屏实现代码
2009/04/09 Javascript
javascript事件冒泡详解和捕获、阻止方法
2014/04/12 Javascript
javascript中解析四则运算表达式的算法和示例
2014/08/11 Javascript
jQuery实现点击后标记当前菜单位置(背景高亮菜单)效果
2015/08/22 Javascript
javascript深拷贝和浅拷贝详解
2017/02/14 Javascript
详解npm 配置项registry修改为淘宝镜像
2018/09/07 Javascript
es6中reduce的基本使用方法
2019/09/10 Javascript
使用layer弹窗提交表单时判断表单是否输入为空的例子
2019/09/26 Javascript
详解vue 组件
2020/06/11 Javascript
python实现下载指定网址所有图片的方法
2015/08/08 Python
python高手之路python处理excel文件(方法汇总)
2016/01/07 Python
python登录并爬取淘宝信息代码示例
2017/12/09 Python
解决Pycharm界面的子窗口不见了的问题
2019/01/17 Python
Python线程之定位与销毁的实现
2019/02/17 Python
Python弹出输入框并获取输入值的实例
2019/06/18 Python
Python使用QQ邮箱发送邮件报错smtplib.SMTPAuthenticationError
2019/12/20 Python
pandas实现DataFrame显示最大行列,不省略显示实例
2019/12/26 Python
python如何实现递归转非递归
2021/02/25 Python
使用HTML5的Canvas绘制曲线的简单方法
2015/09/08 HTML / CSS
One.com挪威:北欧成长最快的网络托管公司
2016/11/19 全球购物
校园活动策划书范文
2014/01/10 职场文书
企业安全生产责任书
2014/04/14 职场文书
工作后的感想
2015/08/07 职场文书
继续教育心得体会(共6篇)
2016/01/19 职场文书
创业计划书之家教中心
2019/09/25 职场文书
SQL Server2019数据库备份与还原脚本,数据库可批量备份
2021/11/20 SQL Server