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.ini中文版(1)
Oct 09 PHP
PHP 学习路线与时间表
Feb 21 PHP
2014过年倒计时示例
Jan 31 PHP
PHP提示Cannot modify header information - headers already sent by解决方法
Sep 22 PHP
php创建、获取cookie及基础要点分析
Jan 26 PHP
PHP数组相加操作及与array_merge的区别浅析
Nov 26 PHP
php正则修正符用法实例详解
Dec 29 PHP
PC端微信扫码支付成功之后自动跳转php版代码
Jul 07 PHP
PHP弱类型语言中类型判断操作实例详解
Aug 10 PHP
Laravel中七个非常有用但很少人知道的Carbon方法
Sep 21 PHP
Laravel获取所有的数据库表及结构的方法
Oct 10 PHP
PHP开发API接口签名生成及验证操作示例
May 27 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
Win9x/ME下Apache+PHP安装配置
2006/10/09 PHP
PHP 一个比较完善的简单文件上传
2010/03/25 PHP
fleaphp crud操作之findByField函数的使用方法
2011/04/23 PHP
PHP GD库生成图像的几个函数总结
2014/11/19 PHP
php如何实现不借助IDE快速定位行数或者方法定义的文件和位置
2017/01/17 PHP
IE中jscript/javascript的条件编译
2006/09/07 Javascript
快速查找数组中的某个元素并返回下标示例
2013/09/03 Javascript
用javascript为页面添加天气显示实现思路及代码
2013/12/02 Javascript
利用了jquery的ajax实现二级联互动菜单
2013/12/02 Javascript
JS中如何设置readOnly的值
2013/12/25 Javascript
项目中常用的JS方法整理
2015/01/30 Javascript
JavaScript 中对象的深拷贝
2016/12/04 Javascript
jquery实现多次上传同一张图片
2017/01/09 Javascript
关于Promise 异步编程的实例讲解
2017/09/01 Javascript
js技巧之十几行的代码实现vue.watch代码
2018/06/09 Javascript
Vue从TodoList中学父子组件通信
2019/02/05 Javascript
微信小程序 checkbox使用实例解析
2019/09/09 Javascript
vue 使用post/get 下载导出文件操作
2020/08/07 Javascript
vue3 watch和watchEffect的使用以及有哪些区别
2021/01/26 Vue.js
[05:49]DOTA2-DPC中国联赛 正赛 Elephant vs LBZS 选手采访
2021/03/11 DOTA
python ip正则式
2009/05/07 Python
Python导入oracle数据的方法
2015/07/10 Python
python3+PyQt5+Qt Designer实现堆叠窗口部件
2018/04/20 Python
Python代码打开本地.mp4格式文件的方法
2019/01/03 Python
对Python3使运行暂停的方法详解
2019/02/18 Python
Python实现计算文件MD5和SHA1的方法示例
2019/06/11 Python
python的几种矩阵相乘的公式详解
2019/07/10 Python
通过实例了解Python str()和repr()的区别
2020/01/17 Python
Django查询优化及ajax编码格式原理解析
2020/03/25 Python
Django 实现将图片转为Base64,然后使用json传输
2020/03/27 Python
Book Depository欧盟:一家领先的国际图书零售商
2019/05/21 全球购物
自我鉴定注意事项
2014/01/19 职场文书
保证书格式范文
2014/04/28 职场文书
12岁生日演讲稿
2014/05/14 职场文书
2014年学生会干事工作总结
2014/11/07 职场文书
劳动保障个人工作总结
2015/03/04 职场文书