1. 概念
Redis hash数据结构是一个键值对(key-value)集合,它是一个 string 类型的 field 和 value 的映射表,redis本身就是一个key-value型数据库,因此hash数据结构相当于在value中又套了一层key-value型数据。所以redis中hash数据结构特别适合存储关系型对象。比如用来存储学生基本信息,或者用户信息等。
2. 常用命令
- hmset 命令:用于同时将多个field-value (字段-值)对设置到哈希表中。假如hash表中已经存在field,则会对其进行覆盖。如果哈希表不存在,会创建一个空哈希表,并执行 HMSET 操作。
- Hmget 命令:用于返回hash表中field字段对应的值,如果field不存在,那么返回nil值。
- Hset 命令:用于对hash表中field对应的value进行赋值,如果哈希表不存在,一个新的哈希表被创建并进行 HSET 操作。
- 用于返回哈希表所有field对应的值。
- Hdel 命令:用于删除指定哈希表中的一个或多个field,不存在的field将被忽略。
- Hgetall 命令:用于返回哈希表中,所有的字段和值。
3. hash类型应用场景
- 购物车:购物车功能主要是通过用户点击商品添加到购物车,前端会传递商品id以及用于需要购买的数据到后端,php通过前端传递的参数进而完成购物车的添加,增加或者减少购物车购买数量,删除或者清空购物车等功能。但如果使用redis来做我们可以使用用户id为key,商品id为field,商品数量为value,恰好构成了购物车的3个要素。部分代码如下:
public function addCart($product,$amount = 1,$user)
{
$key = "cart:$user:product";
if (Redis::exists($key)) { //判断key是否已存在
return Redis::Hmset($key,$product,$amount); //Redis新增hash类型数据做购物车添加
} else {
return Redis::hIncrBy($key,$product,$amount); //已存在就对数量增加,默认为1
}
}
public function DecrCart($product,$amount = -1,$user)
{
$key = "cart:$user:product";
if (Redis::exists($key)) {
return Redis::hIncrBy($key,$product,$amount); //若存在,减掉数量
} else {
return ["status" => true,"message" => "商品未加入购物车"];
}
}
- 存储对象:hash类型的(key, field, value)的结构与对象的(对象id, 属性, 值)的结构相似,因此也可以用来存储对象。string + json也是存储对象的一种方式,那么存储对象时,到底用string + json还是用hash呢?下面我们做一个比较:
string+json | hash | |
---|---|---|
效率 | 很高 | 高 |
容量 | 低 | 低 |
灵活性 | 低 | 高 |
序列化 | 简单 | 复杂 |
综上所述:
- 当对象的某个属性需要频繁修改时,不适合用string+json,因为它不够灵活,每次修改都需要重新将整个对象序列化并赋值,如果使用hash类型,则可以针对某个属性单独修改,没有序列化,也不需要修改整个对象。比如,商品的价格、销量、关注数、评价数等可能经常发生变化的属性,就适合存储在hash类型里。
- 当然,不常变化的属性存储在hash类型里也没有问题,比如商品名称、商品描述、上市日期等。但是,当对象的某个属性不是基本类型或字符串时,使用hash类型就必须手动进行复杂序列化,比如,商品的标签是一个标签对象的列表,商品可领取的优惠券是一个优惠券对象的列表(如下图所示)等,即使以coupons(优惠券)作为field,value想存储优惠券对象列表也还是要使用json来序列化,这样的话序列化工作就太繁琐了,不如直接用string + json的方式存储商品信息来的简单。