list类型是用来存储多个有序的字符串的,列表当中的每一个字符看做一个元素,一个列表当中可以存储一个或者多个元素,redis的list支持存储2^32-1个元素。redis可以从列表的两端进行插入(pubsh)和弹出(pop)元素,支持读取指定范围的元素集,或者读取指定下标的元素等操作。redis列表是一种比较灵活的链表数据结构,它可以充当队列或者栈的角色。
redis列表是链表型的数据结构,所以它的元素是有序的,而且列表内的元素是可以重复的。意味着它可以根据链表的下标获取指定的元素和某个范围内的元素集。
list类型结构实现主要是依据链表 和压缩列表。
下面是插入了"hello"、"world"、"redis" 三个元素的链表结构:
压缩列表的构成:
Zlbytes:压缩列表占用的内存字节数
Zltail:压缩列表尾结点距离起始地址有多少个字节
zllen:压缩列表节点数
entryX:压缩列表节数
Zlend:压缩列表末端
压缩列表节点的构成:
Previous_entry_length:压缩列表前一个节点的长度
encoding:当前节点的值的类型与长度
Content:当前节点的值
压缩列表的遍历(表尾遍历到表头):
List应用场景
list类型的brop和rpush(或者反过来,lpush和rpop)能实现队列的功能,故而可以用Redis的list类型实现简单的点对点的消息队列。
秒杀抢购:某个商品限制在一个时间段,以低价进行售卖。
问题:
1.超卖
2.高并发
3.恶意请求
list类型的lrange命令可以分页查看队列中的数据。可将每隔一段时间计算一次的排行榜存储在list类型中,如京东每日的手机销量排行、学校每次月考学生的成绩排名、斗鱼年终盛典主播排名等。
hash类型基础
redis hash数据结构是一个键值对(key-value)集合,它是一个string类型的field和value的映射表,redis本身就是一个key-value型数据库,因此hash数据结构相当于在value中又套了一层key-value型数据。所以redis中hash数据结构特别适合存储关系型对象。比如用来存储学生基本信息,或者用户信息等。
hash类型基于什么实现?
1.压缩列表
2.Hash表
字典又称符号表,关联数组或者映射,是一种用于保存键值对的抽象数据结构。
字典中的每个键都是独一无二的,程序可以在字典中根据键值查找与之关联的值,或者通过键来更新值,删除等。
type属性是一个指向dicType结构的指针,每个dicType用于操作特定类型键值对的函数,redis会为用途不同的字典设置不同的类型特定函数。
privdata属性则保存了需要传给那些类型特定函数的可选参数。
table属性是一个数组,数组中的每个元素都是一个指向dict.h/dictEntry结构的指针,每个dictEntry结构保存着一个键值对
size属性记录了哈希表的大小,也是table数组的大小
used属性则记录哈希表目前已有节点(键值对)的数量
sizemask属性的值总是等于size-1(从0开始),这个属性和哈希值一起决定一个键应该被放到table数组的哪个索引上面(索引下标值)。
Hash应用场景
购物车功能主要是通过用户点击商品添加到购物车,前端会传递商品id以及用于需要购买的数据到后端,php通过前端传递的参数进而完成购物车的添加,增加或者减少购物车购买数量,删除或者清空购物车等功能。
如果说是使用redis来做我们可以以用户id为key,商品id为field,商品数量为value,恰好构成了购物车的3个要素。
热点的关键字段用hash。
常用命令
hmset userinfo name "xx" age 10 sex 1 //hmset 设置
hmget userinfo name //查询名字
hmget userinfo age //查询年龄
hmget uesrinfo sex //查询性别
hset userinfo name "harry" //修改名字为"harry"
hset productinfo name shouji //设置商品信息中名字为手机
hdel productinfo name //删除商品信息中名字
hgetall userinfo //查询用户信息所有字段
hincrby productinfo stock 1 //修改产品信息中个数(hincrby 自增)
hmget productinfo stock //查询商品信息中返回个数
systemctl stop firewalld
hash类型的{key,field,value}的结构与对象的(对象id,属性,值)的结构类似,也可以用来存储对象。
在介绍string类型的应用场景时有所介绍,string+json也是存储对象 的一种方式。
两种存储方式对比表:
string+json | hash | |
---|---|---|
效率 | 很高 | 高 |
容量 | 低 | 低 |
灵活性 | 低 | 高 |
序列化 | 简单 | 复杂 |
cart.php
<?php
$user_id = $_GET["user_id"];
$product_id = $_GET["product_id"];
$number = $_GET["number"];
$cartKey = "productCart::".$user_id; # 购物车的key 使用用户id与字符串组成 查询的时候也需要加上用户id
$productFiled = "product::".$product_id;# 购物车的商品 使用商品id与字符串组成 购买下单等操作需要加上商品id
/**
* @return Redis
* 友情提示: php使用redis 需要安装redis扩展 是phg安装redis扩展 不是系统安装redis
*/
function RedisConnect()
{
$redis = new Redis();
$redis->connect("127.0.0.1",6379);
return $redis;
}
$redis = RedisConnect();
if ($number == null or $number == 0){
$number = 1;
}
$redis->hIncrBy($cartKey,$productFiled,$number);
echo "加入购物车成功";
index.php
php
<?php
//echo "Hello World !";
//秒杀功能-处理方案
//1. 前端
//1.1 随机拒绝算法 => 用户点击抢购按钮之后,随机0 1 1通过 0不通过
//1.2 根据用户的id => 双数和单数之分 => 双数抢 单数直接拒绝 10 100
//总共 10 万人
//双数 10000
//单数 90000
//2. nginx
//2.1 nginx+redis+lua 进行算法限流 1 秒 1000个 => 中间在写个随机拒绝的算法
//
//3. php
//redis => 将抢购信息写入到list数据中
//库存的更新先不更新mysql => 先更新redis中的库存
//
//4. 应对黑白名单
//使用nginx+Lua+redis 做黑白名单 抢购必须进行实名+实名之后在绑定手机
//
//redis做秒杀
//1. 削峰限流
//2. 使用简单
//3. 高并发
//
//消息队列还有其他 rabbitmq kafak redis的stream类型等
//name => { filed1 => value,
// filed2 => value,
// filed3 => value }