什么是redis
redis是一个key-value存储系统。
我们可以用redis做些什么
1.多种数据类型的存储,相对于memcache,redis支持更多的数据类型
2.持久化,redis可以将数据保存到磁盘,并且在redis出现故障时,可以很好的保存数据,进行回滚或者重写。
3.主从复制
4.集群
5.哨兵
redis的优点
. 速度快
redis的所有数据都是放到内存里的,这也是为什么会速度快的原因
redis是单线程架构
简单稳定
redis不需要依赖系统的类库。每种编程语言都有一套完整的支持redis运行的语法。
————数据类型————-
string类型
简介
String类型是redis的最基础的数据结构,也是最经常使用到的类型。而且其他的四种类型多多少少都是在字
符串类型的基础上构建的,所以String类型是redis的基础。
string 类型的值最大能存储 512MB,这里的String类型可以是简单字符串、复杂的xml/json的字符串、二进
制图像或者音频的字符串、以及可以是数字的字符串。
语法:(基于laravel)
$redis = app('redis.connect') ; //链接redis
$redis->set("redis",456) ; //set操作如果键名存在,则会覆盖原有的值 ;
$redis->get('redis') ;
$array = ['a'=>1,
'b'=>2,
'c'=>3];
$redis->mset($array) ; //存储多个key对应的value
$redis->mget(array_keys($array)) ; //获取多个key对应的Value
$redis->setex('redis2',10,'753') ; //存放带时间的记录
$redis->setnx('redis3',555) ; // 饭回true add操作。不会覆盖已有的值
$redis->setnx('redis3',465) ; //返回false
$redis->getset('redis3',753) ; //get的变种,返回修改之前的值。如果不存在之前的记录,则返回null
$redis->incr('redis3'); //自增 ,返回754 且 redis == 754
$redis->incrby('redis3',2); // 一次增2
$redis->exists('redis'); // 检测是否存在某值
$redis->del('redis2') ; //删除某值
$redis->type('redis2') ; //检测类型,
$redis->append('redis3','_123') ; // 链接已有的字符串,并进行拼接重写 返回拼接后的字符串长度
$redis->setrange($redis,2,'123') ; //返回新的字符串长度
$redis->substr('redis3',2,5) ; //部分获取 表示从第二起到第五个
$redis->setbit('redis3',3,6); //位操作 表示在第三位插入6
$redis->getbit('redis3',3); // 返回6
$redis->strlen('redis3') ; //获取字符串长度
$redis->keys('redis*') ;
$redis->keys('r?dis?') ; //匹配一个字符
$redis->redomkey() ; //随机返回一个key值 ;
$redis->rename('redis3','redis5') ; //修改key值
$redis->renamenx('redis3,"redis4') ; //不允许该车给已经纯在的key
$redis->expire('redis3',10);
$redis->ttl('redis3') ; //获取剩余时间
$redis->persisit('redis3') ; //取消expire操作
$redis->dbsize(); //返回当前redis仓库中的记录总数
string类型的应用场景
session共享
简言之,一个分布式web服务中,讲session放到一台redis中进行集中管理。
处理的问题。分布式服务中,负载均衡会把用户的请求分配到不同的服务器中,当用户的请求和session不在一个服务器时,系统会认为session里面的用户信息不存在,即需要用户重新登录。
计数器
eg.商品浏览记录(后续会更新成代码)
//计数器
public function num()
{
$redis = app('redis.connection');
$str = 'num';
$redis->set($str, 0);
$redis->INCR($str);
$num = $redis->get($str);
echo '-----当前数量为' . $num . "-----";
}
操作限制
eg.一分钟内发送请求的次数
public function SpeedLimit()
{
// $phone = request('phone') ;
$phone = '158xxxxxxx26' ;
$user_id = session('user_id') ?? 1;
$key = "user:$user_id:$phone" ; //根据手机号和用户id 生成标识
if(!$this->redis->get($key)){ //查询该标识是否存在
$user_request = $this->redis->set($key,1,60) ; //限定六十秒内的用户请求次数
if(empty($user_request) || $this->redis->incr($key) < 3 ){
return true ;
}else{
return back()->with('请求次数过多,请稍后重试') ;
}
}
}
list数据类型
简介
list类型是用来存储多个有序的字符串的,列表当中的每一个字符看做一个元素,一个列表当中可以存储有
一个或者多个元素,redis的list支持存储232次方-1个元素。redis可以从列表的两端进行插入(pubsh)和
弹出(pop)元素,支持读取指定范围的元素集,或者读取指定下标的元素等操作。redis列表是一种比较灵
活的链表数据结构,它可以充当队列或者栈的角色。
补充
redis列表是链表型的数据结构,所以它的元素是有序的,而且列表内的元素是可以重复的。意味着它可以
根据链表的下标获取指定的元素和某个范围内的元素集。
redis的list是链表结构所以lpop命令正是取出列表的第一个元素,如果list当中没有没有元素,会
一直等待到超时,或者发现有数据为止。
语法
//队列操作
//rpush/rpushx有序列表操作,从队列后插入元素;lpush/lpushx和rpush/rpushx的区别是插入到队列的头部
// ,'x'的含义是只对已存在的key进行操作
$redis->rpush('redisList','one') ;
$redis->lpush('redisList','two') ;
$redis->rpushx('redisList','three') ; //只对已存在的队列做添加,否则返回0
$redis->llen('redisList') ; //返回 3
$redis->lindex('redisList',2) ; //返回指定顺序位置的list元素
$redis->lset('redisList',2,'four') ; //修改队列中指定位置的value
$redis->lrem('redisList',2,'example') ; // 删除队列从做起第二个字符(example)
//删除队列中左起指定数量的字符
$redis->lrem('redisList',-1,'ah') ; //从右起删除一个 ah
$redis->rpop('redisList') ; //类似栈结构地弹出并和三处最右的一个元素
$redis->rpop('redisList') ; //类似栈结构的弹出并删除最左的一个元素
$redis->ltrim('redisList',2,4) ; //保留从左起第二个到第四个元素,其余删除
list类型应用场景
秒杀抢购
list类型的lpop和rpush(或者反过来,lpush和rpop)能实现队列的功能,故而可以用Redis的list类型实现简
单的点对点的消息队列。(如果对数据的安全性要求不是很高的情况下)
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Redis;
class SecKillController extends Controller
{
//
public function __construct()
{
$goodsId = 1; //假设参与抢购的商品id = 1
$this->user_queue_key = "buyers:{$goodsId}:";//抢购成功队列的key 使用redis 的hash方式储存
$this->goods_num_key = "goods:$goodsId"; //商品库存key 使用redis 的list方式存储
}
public function index()
{
$orders = Redis::hgetall($this->user_queue_key); //获取该商品所有参与抢购的订单信息
foreach ($orders as $k => $order) {
$orders[$k] = unserialize($order);
}
return view('home', compact('orders'));
}
/*
* 秒杀
* */
public function SecKill()
{
//判断抢购商品队列中是否有该用户id
$isHaveQueue = Redis::hexists($this->user_queue_key, auth()->id());
if ($isHaveQueue) {
return back()->with('msg', '您已抢购');
}
$count = Redis::rpop($this->goods_num_key); //返回取出一个后剩余的商品数量
if (!$count) { //没货 抢购失败
return back()->with('msg', '已经抢光');
}
$this->SuccessUserQueue(auth()->id()); //有货 加入抢购成功的用户id
return back()->with('msg', '抢购成功');
}
/*
*抢购成功的客户加入队列
*
* */
public function SuccessUserQueue($uid)
{
//生成唯一订单
$orderNo = $this->buildOrderNo();
$userQueue = [
'user_id' => auth()->id(),
'user_name' => Auth::user()->name,
'order_num' => $orderNo,
'created_at' => time(),
];
$userQueue = serialize($userQueue);
Redis::hset($this->user_queue_key, $uid, $userQueue);
return true;
}
/*
* 生成唯一订单号
*
* */
public function buildOrderNo()
{
return
date('ymd') . substr(implode(NUll, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
}
public function goodsQueue()
{
$store = 100;
$goodsLen = Redis::llen($this->goods_num_key);
$count = $store - $goodsLen <= 0 ? 0 : $store - $goodsLen;
for ($i = 0; $i < $count; $i++) {
Redis::lpush($this->goods_num_key, 1);
}
echo '目前库存:' . Redis::llen($this->goods_num_key) . "</br>";
}
}
排行榜(非动态排行榜)
eg,历史排行 周排行
.### hash数据类型与结构
hash数据结构 是一个键值对(key-value)集合,它是一个 string 类型的 field 和 value 的映射表(简单理解,相当于双层key-value结构)
语法
$redis->hset('article:1','title','文章1');
$redis->hset('artical:1','content','study') ;
//利用散列存储文章信息
$redis->hmset('article:1',['title'=>'文章1','link'=>'111','poster'=>'user1','time'=>'2222','votes'=>555]);
//根据发布时间排列文章的有序集合
$redis->zadd('article:1',2222);
$redis->zset('artical:2',3333) ;
$redis->zset('article:3',5555);