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安装全攻略:APACHE
Oct 09 PHP
超级简单的发送邮件程序
Oct 09 PHP
在JavaScript中调用php程序
Mar 09 PHP
php win下Socket方式发邮件类
Aug 21 PHP
浅谈PHP解析URL函数parse_url和parse_str
Nov 11 PHP
php使用str_replace实现输入框回车替换br的方法
Nov 24 PHP
ThinkPHP连接数据库的方式汇总
Dec 05 PHP
php读取csc文件并输出
May 21 PHP
LINUX下PHP程序实现WORD文件转化为PDF文件的方法
May 13 PHP
PHP上传图片、删除图片简单实例
Nov 12 PHP
PHP Ajax跨域问题解决方案代码实例
Aug 01 PHP
php实现微信和支付宝支付的示例代码
Aug 11 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语法(3)
2006/10/09 PHP
用Flash图形化数据(一)
2006/10/09 PHP
php adodb分页实现代码
2009/03/19 PHP
PHP JSON 数据解析代码
2010/05/26 PHP
PHP数据流应用的一个简单实例
2012/09/14 PHP
php笔记之:php函数range() round()和list()的使用说明
2013/04/26 PHP
php与java通过socket通信的实现代码
2013/10/21 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(七)
2014/06/23 PHP
CI(Codeigniter)的Setting增强配置类实例
2016/01/06 PHP
PHP socket 模拟POST 请求实例代码
2016/07/18 PHP
使用Modello编写JavaScript类
2006/12/22 Javascript
Javascript this 函数深入详解
2016/12/13 Javascript
JS闭包用法实例分析
2017/03/27 Javascript
JS实现静态页面搜索并高亮显示功能完整示例
2017/09/19 Javascript
对vue中methods互相调用的方法详解
2018/08/30 Javascript
H5+C3+JS实现五子棋游戏(AI篇)
2020/05/28 Javascript
解决React在安装antd之后出现的Can't resolve './locale'问题(推荐)
2020/05/03 Javascript
vue-router的hooks用法详解
2020/06/08 Javascript
[01:37]全新的一集《真视界》——TI7总决赛
2017/09/21 DOTA
[57:22]完美世界DOTA2联赛PWL S2 FTD vs PXG 第二场 11.27
2020/12/01 DOTA
浅谈Python中数据解析
2015/05/05 Python
Python提取网页中超链接的方法
2016/09/18 Python
Python2和Python3中print的用法示例总结
2017/10/25 Python
在Django下创建项目以及设置settings.py教程
2019/12/03 Python
HTML5中的网络存储实现方式
2020/04/28 HTML / CSS
Wallis官网:英国女装零售商
2020/01/21 全球购物
高三学生评语大全
2014/04/25 职场文书
房地产开发项目建议书
2014/05/16 职场文书
校园环保标语
2014/06/13 职场文书
优秀团员事迹材料2000字
2014/08/20 职场文书
作文评语怎么写
2014/12/25 职场文书
小学生交通安全寄语
2015/02/27 职场文书
毕业证明模板
2015/06/19 职场文书
厉行节约工作总结
2015/08/12 职场文书
Golang Gob编码(gob包的使用详解)
2021/05/07 Golang
聊聊mysql都有哪几种分区方式
2022/04/13 MySQL