一、特性说明
基本特性说明
- 每个hash可以存储2^32-1个f-v
- hash的field是key的子元素,field不存在,key也不存在。
- hash的映射关系适合用于存储对象
- hash结构是可以压缩的,相比string类型来说,会比较节省内存。
某key的field数量>hash-max-zipmap-entries 采用正常内存存储
某key的field的某value > hash-max-zipmap-value 采用正常内存存储
某key的field数量 < hash-max-zipmap-entries 采用zipmap压缩存储
某key的field的某value < hash-max-zipmap-value 采用zipmap压缩存储
优点和缺点
优点:
- 同类数据归类整合存储,方便数据管理
- 相比string操作消耗的内存和cpu更小
- 相比string存储更节省空间
缺点:
- 过期功能不能使用在field上,只能用在key上
- redis集群架构下不适合大规模使用
二、常用命令
(一)HSET
命令格式: hset key field value
功能:一个哈希表key中存入一个键值对
demo说明:
(二)HGET
命令格式: hget key field
功能:一个哈希表key中取出一个键值对
demo说明:
(三)HSETNX
命令格式: hsetnx key field value
功能:存入一个不存在的哈希表key的键值
demo说明:
(四)HMSET
命令格式: hset key field value [field value]
功能:在一个哈希表key中存入多个键值对
demo说明:
(五)HMGET
命令格式: hget key field [field]
功能:在一个哈希表key中取出多个键值对
demo说明:
(六)HDEL
命令格式: hdel key field [field]
功能:删除哈希表中key对应的field键值
demo说明:
(七)HLEN
命令格式: hlen key
功能:返回哈希表中key对应的filed个数
demo说明:
(八)HGETALL
命令格式: hset key field value
功能:返回哈希表中key所有的键值
demo说明:
三、应用场景
(一)对象数据缓存
说明:系统中对象有多属性并且业务常用获取值判断的场景
1、需求
将用户信息缓存,减少查询数据库
2、设计
- 登录查询到用户信息,缓存进redis
- 登出将用户信息从缓存销毁
- 缓存键设计为 {user}:{用户id}
3、开发
登录存储用户信息
@PostMapping("/test/login")
public void testLogin() throws Exception {
String key="user:1000";
//从数据库查询到用户信息
Users users = new Users();
users.setMobile("13800138000");
users.setNickname("张三");
//这里大家可以在users的内部实现一个tomap方法 我这里为了简单就随便写
HashMap<String, Object> map = new HashMap<>(16);
map.put("mobile",users.getMobile());
map.put("nickName",users.getNickname());
//批量存入,相当于redis的命令 hmset
redisTemplate.opsForHash().putAll(key,map);
}
业务需要获取用户信息
@PostMapping("/test/getUserInfo")
public void getUserInfo() throws Exception {
String key="user:1000";
//键值user里面有多个属性,可以根据自己的需要获取
List<String> list = new ArrayList<>();
list.add("mobile");
list.add("nickName");
List result = redisTemplate.opsForHash().multiGet(key, list);
System.out.println(result);
}
退出登录时候将缓存信息删除
@PostMapping("/test/logout")
public void testlogout() throws Exception {
String key="user:1000";
//直接把键值删掉即可
redisTemplate.delete(key);
}
(二)实现演唱会抢票功能
说明:这里主要实现抢票这个环境,不包括前后各种时间判断以及数据落库等等
1、需求
实现抢票功能
2、设计
- 首先创建场次票务时把座位信息加入缓存
- 用户锁定座位时判断是否缓存设置成功,成功表示成功锁定
- 座位集合缓存键设计为 {业务}:{表名}:{场次id}
- 用户锁定缓存键设计为 user:{业务}:{表名}:{场次id}
3、开发
初始化数据,抢票开始前会将场次的座位号放进缓存的一个集合中,这里用到数据结构set,后面的篇章会讲到
@PostMapping("/test/activeBefore")
public void activeBefore() throws Exception {
//键值 业务:表名:场次id
String setkey="purchase:ticket:1000";
//从数据库获取座位号,这里随便设几个意思意思
List<String> data = Arrays.asList("A-01","A-02","A-03","A-04","A-05");
String[] seat =new String[data.size()];
for (int i = 0; i < data.size(); i++) {
seat[i] = data.get(i);
}
//存入缓存
redisTemplate.opsForSet().add(setkey,seat);
}
用户抢购电影票
@PostMapping("/test/buyTicket")
public void buyTicket(Integer id,String seatNum) throws Exception {
//键值 业务:表名:场次id 这里的键值设置比较简单,具体要自身业务
String setkey="purchase:ticket:"+id.toString();
String buykey="user:purchase:ticket:"+id.toString();
//判断传进来的座位号是否正确,判断集合中是否存在
Boolean isMember = redisTemplate.opsForSet().isMember(setkey, seatNum);
if(!isMember){
System.out.println("座位信息有误");
return ;
}
//抢票,若返回成功,则表示成功锁定席位
Boolean result = redisTemplate.opsForHash().putIfAbsent(buykey,seatNum, "1");
if(result){
System.out.println("锁定席位成功");
}else{
System.out.println("该座位已有人购买");
}
}
(三)电商用户购物车
后续有需要补上