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 28 PHP
php 获取全局变量的代码
Apr 21 PHP
PHP文章采集URL补全函数(FormatUrl)
Aug 02 PHP
PHP rawurlencode与urlencode函数的深入分析
Jun 08 PHP
PHP实现读取一个1G的文件大小
Aug 24 PHP
php数组操作之键名比较与差集、交集赋值的方法
Nov 10 PHP
PHP简单实现断点续传下载的方法
Sep 25 PHP
php实现通过soap调用.Net的WebService asmx文件
Feb 27 PHP
PHP实现防止表单重复提交功能【基于token验证】
May 24 PHP
YII2框架中使用RBAC对模块,控制器,方法的权限控制及规则的使用示例
Mar 18 PHP
Laravel框架数据库迁移操作实例详解
Apr 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通过header实现文本文件下载的代码
2010/08/08 PHP
对于ThinkPHP框架早期版本的一个SQL注入漏洞详细分析
2014/07/04 PHP
CI框架Session.php源码分析
2014/11/03 PHP
Yii2.0高级框架数据库增删改查的一些操作
2015/11/16 PHP
php字符串的替换,分割和连接方法
2016/05/23 PHP
Yii框架 session 数据库存储操作方法示例
2019/11/18 PHP
自己开发Dojo的建议框架
2008/09/24 Javascript
javascript 异常处理使用总结
2009/06/21 Javascript
jquery.validate使用攻略 第二部
2010/07/01 Javascript
jQuery.extend 函数详解
2012/02/03 Javascript
中国地区三级联动下拉菜单效果分析
2012/11/15 Javascript
输入密码检测大写是否锁定js实现代码
2012/12/03 Javascript
JS的Document属性和方法小结
2013/09/17 Javascript
javascript中sort()的用法实例分析
2015/01/30 Javascript
简单了解Backbone.js的Model模型以及View视图的源码
2016/02/14 Javascript
Javascript在IE和Firefox浏览器常见兼容性问题总结
2016/08/03 Javascript
Google 地图控件集详解及实例代码
2016/08/06 Javascript
angular过滤器实现排序功能
2017/06/27 Javascript
JS解决IOS中拍照图片预览旋转90度BUG的问题
2017/09/13 Javascript
基于node.js实现微信支付退款功能
2017/12/19 Javascript
ant design vue嵌套表格及表格内部编辑的用法说明
2020/10/28 Javascript
Python实现遍历windows所有窗口并输出窗口标题的方法
2015/03/13 Python
修复CentOS7升级Python到3.6版本后yum不能正确使用的解决方法
2018/01/26 Python
Python使用遗传算法解决最大流问题
2018/01/29 Python
Python BS4库的安装与使用详解
2018/08/08 Python
python学习——内置函数、数据结构、标准库的技巧(推荐)
2019/04/18 Python
python 消除 futureWarning问题的解决
2019/12/25 Python
在python3中实现查找数组中最接近与某值的元素操作
2020/02/29 Python
python3+openCV 获取图片中文本区域的最小外接矩形实例
2020/06/02 Python
Python3 requests模块如何模仿浏览器及代理
2020/06/15 Python
Python正则表达式高级使用方法汇总
2020/06/18 Python
解决python打开https出现certificate verify failed的问题
2020/09/03 Python
怎样写好自我评价呢?
2014/02/16 职场文书
2015年小学校长工作总结
2015/05/19 职场文书
创业计划书之网吧
2019/10/10 职场文书
2020年元旦祝福语录,总有适合你的
2019/12/31 职场文书