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 分页原理分析,大家可以看看
Dec 21 PHP
php iconv() : Detected an illegal character in input string
Dec 05 PHP
PHP源码之explode使用说明
Aug 05 PHP
关于PHP递归算法和应用方法介绍
Apr 15 PHP
PHP 转义使用详解
Jul 15 PHP
php查找字符串出现次数的方法
Dec 01 PHP
php include类文件超时问题处理
Feb 06 PHP
PHP中实现Bloom Filter算法
Mar 30 PHP
PHP借助phpmailer发送邮件
May 11 PHP
Apache服务器下防止图片盗链的办法
Jul 06 PHP
php微信公众号开发之二级菜单
Oct 20 PHP
php 根据URL下载远程图片、压缩包、pdf等文件到本地
Jul 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
用PHP实现小型站点广告管理(修正版)
2006/10/09 PHP
php微信高级接口调用方法(自定义菜单接口、客服接口、二维码)
2016/11/28 PHP
PHP 获取客户端 IP 地址的方法实例代码
2018/11/11 PHP
PHP7 标准库修改
2021/03/09 PHP
TFDN图片播放器 不错自动播放
2006/10/03 Javascript
JQuery验证jsp页面属性是否为空(实例代码)
2013/11/08 Javascript
js 事件截取enter按键页面提交事件示例代码
2014/03/04 Javascript
JavaScript学习心得之概述
2015/01/20 Javascript
JQuery自适应窗口大小导航菜单附源码下载
2015/09/01 Javascript
AngularJS基础 ng-keydown 指令简单示例
2016/08/02 Javascript
关于angularJs指令的Scope(作用域)介绍
2016/10/25 Javascript
jQuery中的deferred使用方法
2017/03/27 jQuery
js前端实现图片懒加载(lazyload)的两种方式
2017/04/24 Javascript
Kindeditor单独调用多图上传实例
2017/07/31 Javascript
react+redux的升级版todoList的实现
2017/12/18 Javascript
angularJS实现动态添加,删除div方法
2018/02/27 Javascript
微信小程序实现图片上传功能
2018/05/28 Javascript
vue 地图可视化 maptalks 篇实例代码详解
2019/05/21 Javascript
微信小程序收藏功能的实现代码
2020/06/19 Javascript
js编写简易的计算器
2020/07/29 Javascript
微信小程序接入vant Weapp组件的详细步骤
2020/10/28 Javascript
[05:08]DOTA2-DPC中国联赛3月6日Recap集锦
2021/03/11 DOTA
浅谈Python中用datetime包进行对时间的一些操作
2016/06/23 Python
Python实现excel转sqlite的方法
2017/07/17 Python
python实现树形打印目录结构
2018/03/29 Python
python3中函数参数的四种简单用法
2018/07/09 Python
win7 x64系统中安装Scrapy的方法
2018/11/18 Python
python匿名函数lambda原理及实例解析
2020/02/07 Python
通过代码实例了解Python异常本质
2020/09/16 Python
万代美国官网:PREMIUM BANDAI USA
2020/09/11 全球购物
中专毕业生自荐信
2013/11/16 职场文书
一份没有按时交货失信于客户的检讨书
2014/09/19 职场文书
公安四风对照检查材料思想汇报
2014/10/11 职场文书
2016年小学生寒假总结
2015/10/10 职场文书
2016年艾滋病宣传活动总结
2016/04/01 职场文书
闭幕词的写作格式与范文!
2019/06/24 职场文书