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在Web开发领域的优势
Oct 09 PHP
PHP新手上路(十二)
Oct 09 PHP
phpMyAdmin 安装及问题总结
May 28 PHP
PHP最常用的ini函数分析 针对PHP.ini配置文件
Apr 22 PHP
php继承的一个应用
Sep 06 PHP
PHP对象转换为数组函数(递归方法)
Feb 04 PHP
php cli 小技巧
Jun 03 PHP
php判断电脑访问、手机访问的例子
May 10 PHP
CI框架中$this-&gt;load-&gt;library()用法分析
May 18 PHP
Yii2实现多域名跨域同步登录退出
Feb 04 PHP
php双层循环(九九乘法表)
Oct 23 PHP
thinkPHP3.2.3实现阿里大于短信验证的方法
Jun 06 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 判断变量类型实现代码
2009/10/23 PHP
php可生成缩略图的文件上传类实例
2014/12/17 PHP
php去掉文件前几行的方法
2015/07/29 PHP
php搜索文件程序分享
2015/10/30 PHP
php遍历解析xml字符串的方法
2016/05/05 PHP
PHP实现从上往下打印二叉树的方法
2018/01/18 PHP
PHP实现递归的三种方法
2020/07/04 PHP
jQuery EasyUI API 中文文档 - NumberBox数字框
2011/10/13 Javascript
js中匿名函数的创建与调用方法分析
2014/12/19 Javascript
在JavaScript应用中实现延迟加载的方法
2015/06/25 Javascript
jquery实现触发时更新下拉列表内容的方法
2015/12/02 Javascript
javascript中的 object 和 function小结
2016/08/14 Javascript
AngularJS 作用域详解及示例代码
2016/08/17 Javascript
JS实现的简易拖放效果示例
2016/12/29 Javascript
React创建组件的三种方式及其区别
2017/01/12 Javascript
十大 Node.js 的 Web 框架(快速提升工作效率)
2017/06/30 Javascript
checkbox:click事件触发span元素内容改变的方法
2017/09/11 Javascript
VUE v-model表单数据双向绑定完整示例
2019/01/21 Javascript
解决vue+webpack项目接口跨域出现的问题
2020/08/10 Javascript
vue实现井字棋游戏
2020/09/29 Javascript
解决vue中使用less/sass及使用中遇到无效的问题
2020/10/24 Javascript
Python利用pandas计算多个CSV文件数据值的实例
2018/04/19 Python
python爬取网页转换为PDF文件
2018/06/07 Python
pycharm在调试python时执行其他语句的方法
2018/11/29 Python
python+flask编写一个简单的登录接口
2020/11/13 Python
火山咖啡:Volcanica Coffee
2019/10/29 全球购物
iHerb俄罗斯:维生素、补品和天然产品
2020/07/09 全球购物
求高于平均分的学生学号及成绩
2016/09/01 面试题
绘画专业自荐信范文
2014/02/23 职场文书
空乘英文求职信
2014/04/13 职场文书
活动策划求职信模板
2014/04/21 职场文书
协议书样本
2014/04/23 职场文书
药店收银员岗位职责
2015/04/07 职场文书
毕业论文致谢信
2015/05/14 职场文书
学会掌握自己命运的十条黄金法则:
2019/08/08 职场文书
golang 如何通过反射创建新对象
2021/04/28 Golang