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 30 PHP
在SAE上搭建最新wordpress的方法
Dec 21 PHP
PHP实现bitmap位图排序与求交集的方法
Jul 28 PHP
PHP读取大文件的几种方法介绍
Oct 27 PHP
PHP常用的三种设计模式
Feb 17 PHP
thinkPHP5.0框架环境变量配置方法
Mar 17 PHP
PHP实现Redis单据锁以及防止并发重复写入
Apr 10 PHP
PHP基于mcript扩展实现对称加密功能示例
Feb 21 PHP
Laravel 5.5 实现禁用用户注册示例
Oct 24 PHP
thinkphp框架实现路由重定义简化url访问地址的方法分析
Apr 04 PHP
PHP利用curl发送HTTP请求的实例代码
Jul 09 PHP
详解Laravel服务容器的优势
May 29 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 rmdir()函数的用法总结
2019/07/02 PHP
基于jQuery实现的百度导航li拖放排列效果,即时更新数据库
2012/07/31 Javascript
jQuery+ajax中getJSON() 用法实例
2014/12/22 Javascript
JavaScript获取并更改input标签name属性的方法
2015/07/02 Javascript
JS基于myFocus库实现各种功能的tab选项卡切换效果
2015/09/19 Javascript
Angular.js如何从PHP读取后台数据
2016/03/24 Javascript
jQuery Mobile页面返回不需要重新get
2016/04/26 Javascript
js阻止默认浏览器行为与冒泡行为的实现代码
2016/05/15 Javascript
JCrop+ajaxUpload 图像切割上传的实例代码
2016/07/20 Javascript
Bootstrap Img 图片样式(推荐)
2016/12/13 Javascript
Angular通过angular-cli来搭建web前端项目的方法
2017/07/27 Javascript
vue跳转页面的几种方法(推荐)
2020/03/26 Javascript
利用Python中的mock库对Python代码进行模拟测试
2015/04/16 Python
Python彩色化Linux的命令行终端界面的代码实例分享
2016/07/02 Python
python学习笔记之列表(list)与元组(tuple)详解
2017/11/23 Python
wxPython实现窗口用图片做背景
2018/04/25 Python
树莓派安装OpenCV3完整过程的实现
2019/10/10 Python
Python实现元素等待代码实例
2019/11/11 Python
使用python绘制cdf的多种实现方法
2020/02/25 Python
pip install 使用国内镜像的方法示例
2020/04/03 Python
基于Python编写一个计算器程序,实现简单的加减乘除和取余二元运算
2020/08/05 Python
关于Kotlin中SAM转换的那些事
2020/09/15 Python
解决pytorch 数据类型报错的问题
2021/03/03 Python
css3实现背景动态渐变效果
2019/12/10 HTML / CSS
美国孕妇装品牌:Destination Maternity
2018/02/04 全球购物
Anthropologie英国:美国家喻户晓的休闲服装和家居产品品牌
2018/12/05 全球购物
凯蒂·佩里个人女鞋品牌:Katy Perry Collections
2019/04/04 全球购物
物流管理应届生求职信
2013/11/07 职场文书
初婚初育证明
2014/01/14 职场文书
公司经理任命书
2014/06/05 职场文书
群教班子对照检查材料
2014/08/26 职场文书
2015年学校管理工作总结
2015/07/20 职场文书
Python利器openpyxl之操作excel表格
2021/04/17 Python
Java中CyclicBarrier和CountDownLatch的用法与区别
2021/08/23 Java/Android
Python3.8官网文档之类的基础语法阅读
2021/09/04 Python
Spring-cloud Config Server的3种配置方式
2021/09/25 Java/Android