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读取目录下所有文件的代码
Jan 07 PHP
php 友好URL的实现(吐血推荐)
Oct 04 PHP
php递归创建目录的方法
Feb 02 PHP
求帮忙修改个php curl模拟post请求内容后并下载文件的解决思路
Sep 20 PHP
Zend Framework教程之前端控制器Zend_Controller_Front用法详解
Mar 07 PHP
CI框架整合widget(页面格局)的方法
May 17 PHP
PHP常用的三种设计模式汇总
Aug 28 PHP
使用正则去除php代码中的注释方法
Nov 03 PHP
PHP实现的曲线统计图表示例
Nov 10 PHP
php魔法函数与魔法常量使用介绍
Jul 23 PHP
PHP多进程简单实例小结
Nov 09 PHP
php设计模式之策略模式实例分析【星际争霸游戏案例】
Mar 26 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
全国FM电台频率大全 - 7 吉林省
2020/03/11 无线电
十天学会php之第六天
2006/10/09 PHP
PHP 八种基本的数据类型小结
2011/06/01 PHP
php按字符无乱码截取中文的方法
2015/03/27 PHP
Symfony2之session与cookie用法小结
2016/03/18 PHP
jquery+thinkphp实现跨域抓取数据的方法
2016/10/15 PHP
thinkphp ajaxfileupload实现异步上传图片的示例
2017/08/28 PHP
PHP闭包定义与使用简单示例
2018/04/13 PHP
提高Laravel应用性能方法详解
2019/06/24 PHP
php 使用ActiveMQ发送消息,与处理消息操作示例
2020/02/23 PHP
PHP设计模式(一)工厂模式Factory实例详解【创建型】
2020/05/02 PHP
Jquery实现视频播放页面的关灯开灯效果
2013/05/27 Javascript
js操作输入框提示信息且响应鼠标事件
2014/03/25 Javascript
前端框架Vue.js中Directive知识详解
2016/09/12 Javascript
jQuery实现可展开折叠的导航效果示例
2016/09/12 Javascript
vue.js树形组件之删除双击增加分支实例代码
2017/02/28 Javascript
vue实现跳转接口push 转场动画示例
2019/11/01 Javascript
vue项目启动出现cannot GET /服务错误的解决方法
2020/04/26 Javascript
vue+axios全局添加请求头和参数操作
2020/07/24 Javascript
Python、Javascript中的闭包比较
2015/02/04 Python
举例讲解Python设计模式编程中对抽象工厂模式的运用
2016/03/02 Python
利用python循环创建多个文件的方法
2018/10/25 Python
对pandas中两种数据类型Series和DataFrame的区别详解
2018/11/12 Python
Python实现插入排序和选择排序的方法
2019/05/12 Python
python实现猜数游戏(保存游戏记录)
2020/06/22 Python
Pyinstaller打包Scrapy项目的实现步骤
2020/09/22 Python
HTML5 Canvas自定义圆角矩形与虚线示例代码
2013/08/02 HTML / CSS
巴西男士个人护理产品商店:SHOP4MEN
2017/08/07 全球购物
银行财务部实习生的自我鉴定
2013/11/27 职场文书
2015年幼儿园毕业感言
2014/02/12 职场文书
关于九一八事变的演讲稿2014
2014/09/17 职场文书
授权委托书样本及填写说明
2014/09/19 职场文书
2016年少先队活动总结
2016/04/06 职场文书
详解Python小数据池和代码块缓存机制
2021/04/07 Python
PYTHON使用Matplotlib去实现各种条形图的绘制
2022/03/22 Python
如何Python使用re模块实现okenizer
2022/04/30 Python