概念:Redis是用C语言开发的一个开源的高性能键值对(Key-value)数据库
特征:
- 数据间没有必然的关联关系
- 内部采用单线程机制进行工作
- 高性能,官方提供测试数据,50个并发执行100000个请求,读的速度是110000次/s,写的速度是81000次/s。
- 多数据类型支持
字符串类型 string
列表类型 list
散列类型 hash
集合类型 set
有序集合类型 sorted_set
5.持久化支持。可以进行数据灾难恢复。
二、Redis的下载与安装
2.1Redis的下载
Linux版(适用于企业级开发)
- Redis高级开始使用
- 以4.0版本作为主板本
Windows版本(适合零基础学习)
- Redis入门使用
- 以 3.2 版本作为主版本
- 下载地址:https://github.com/MSOpenTech/redis/tags
2.2安装Redis
核心文件:
redis-server.exe 服务器启动命令
redis-cli.exe 命令行客户端
redis.windows.conf redis核心配置文件
redis-benchmark.exe 性能测试工具
redis-check-aof.exe AOF文件修复工具
redis-check-dump.exe RDB文件检查工具(快照持久化文件)
2.3启动Redis
服务器启动
方式1:双击redis-server.exe
方式2:指令redis-server.exe redis.windows.conf
客户端连接
三、Redis数据类型(5种常用)
5.1String
- 存储的数据:单个数据,最简单的数据存储类型,也是最常用的数据存储类型
- 存储数据的格式:一个存储空间保存一个数据
- 存储内容:通常使用字符串,如果字符串以整数的形式展示,可以作为数字操作使用
业务场景一:========================================================== 大型 大型企业级应用中,随着数据量的递增,分表操作是基本操作,使用多张表存储同类型数据,但是对应的主键 id 必须保证统一性,不能重复。Oracle 数据库具有 sequence 设定,可以解决该问题,但是 MySQL数 据库并不具有类似的机制,那么如何解决?
设置数值数据增加指定范围的值
incr key
incrby key increment
incrbyfloat key increment
设置数值数据减少指定范围的值
decr key
decrby key increment
业务场景二:==========================================================
“中国有嘻哈”启动海选投票,只能通过微信投票,每个微信号每 4 小时只能投1票。
电商商家开启热门商品推荐热门商品不能一直处于热门,每种商品热门期维持3天,3天后自动取消热门。 新闻网站会出现热点新闻,热点新闻最大的特征是时效性,如何自动控制热点新闻的时效性。
设置数据具有指定的生命周期
setex key seconds value psetex key milliseconds value
设置key的过期时间
EXPIRE key seconds
查看key的剩余时间
ttl key
Tips 2:
redis 控制数据的生命周期,通过数据是否失效控制业务行为,适用于所有具有时效性限定控制的操作
业务场景三:========================================================== 主页高频访问信息显示控制,例如新浪微博大V主页显示粉丝数与微博数量
关注数focuss 粉丝数fans 微博数blogs 解决方案
在redis中为大V用户设定用户信息,以用户主键和属性值作为key,后台设定定时刷新策略即可
eg: user:id:3506728370:fans → 12210947
eg: user:id:3506728370:blogs → 6164
eg: user:id:3506728370:focuss → 83
在redis中以json格式存储大V用户信息,定时刷新(也可以使用hash类型)
eg: user:id:3506728370 → {"id":3506728370,"name":"春晚","fans":12210862,"blogs":6164, "focus":83}
Tips 3:redis应用于各种结构型和非结构型高热度数据访问加速 key 的设置约定===数据库中的热点数据key命名惯例 表名:主键名:主键值:字段名
eg: order:id:9527:name : 王瑞豪
注意事项:========================================================== 数据操作不成功的反馈与数据正常操作之间的差异
① 表示运行结果是否成功 (integer) 0 → false 失败 (integer) 1 → true 成功
② 表示运行结果值
(integer) 3 → 3 3个
(integer) 1 → 1 1个
数据未获取到
(nil)等同于null
数据最大存储量
512MB
数值计算最大范围(java中的long的最大值)
9223372036854775807
5.2hash
存储的困惑
对象类数据的存储如果具有较频繁的更新需求操作会显得笨重
hash哈希特点
- 新的存储需求:对一系列存储的数据进行编组,方便管理,典型应用存储对象信息
- 需要的存储结构:一个存储空间保存多个键值对数据
- hash类型:底层使用哈希表结构实现数据存储
hash存储结构优化
- 如果filed数量较少,存储结构优化为类数组结构
- 如果field数量较多,存储结构使用HashMap结构
==========================hash哈希类型========================== 添加/修改数据
hset key field value
获取数据
hget key field hgetall key
删除数据
hdel key field1 [field2]
获取哈希表中字段的数量
hlen key
获取哈希表中所有的字段名或字段值
hkeys key hvals key
hash 类型数据操作的注意事项
1.hash类型下的value只能存储字符串,不允许存储其他数据类型,不存在嵌套现象。如果数据未获取 到,对应的值为(nil)
2.每个 hash 可以存储 2^32^-1个键值对
3.hash类型十分贴近对象的数据存储形式,并且可以灵活添加删除对象属性。但hash设计初衷不是为了 存储大量对象而设计的,切记不可滥用,更不可以将hash作为对象列表使用
4.hgetall 操作可以获取全部属性,如果内部field过多,遍历整体数据效率就很会低,有可能成为数 据访问瓶颈
业务场景一:========================================================== string存储对象(json)与hash存储对象 Stirng存对象强调整体性一般用于读 hash存对象强调灵活性一般用于写
业务场景二:==========================================================
电商网站购物车设计与实现 购物车的redis存储模型 添加、浏览、更改数量、删除、清空
解决方案
- 以客户id作为key,每位客户创建一个hash存储结构存储对应的购物车信息
- 将商品编号作为field,购买数量作为value进行存储
- 添加商品:追加全新的field与value
- 浏览:遍历hash
- 更改数量:自增/自减,设置value值
- 删除商品:删除field
- 清空:删除key
5.3List
- 数据存储需求:存储多个数据,并对数据进入存储空间的顺序进行区分
- 需要的存储结构:一个存储空间保存多个数据,且通过数据可以体现进入顺序
- list类型:保存多个数据,底层使用双向链表存储结构实现
==========================list========================== 添加/修改数据
lpush key value1 [value2] ……
rpush key value1 [value2] ……
获取数据
lrange key start stop
lindex key index
llen key
获取并移除数据
lpop key rpop key
通过下标截取指定的长度,这个list已经被改变了,只剩下截取的元素
ltrim key start end
lset将列表中指定下标的值替换为另外一个值,更新操作
lset key 下标 新数据 # 如果不存在列表我们去更新就会报错
list 类型数据操作注意事项
1.list中保存的数据都是string类型的,数据总容量是有限的,最多2^32^-1个元素 (4294967295)
2.list具有索引的概念,但是操作数据时通常以队列的形式进行入队出队操作,或以栈的形式进行入栈出 栈操作
3.获取全部数据操作结束索引设置为-1
4.list可以对数据进行分页操作,通常第一页的信息来自于list,第2页及更多的信息通过数据库的形式加 载
5.4Set
- 新的存储需求:存储大量的数据,在查询方面提供更高的效率
- 需要的存储结构:能够保存大量的数据,高效的内部存储机制,便于查询
- set类型:与hash存储结构完全相同,仅存储键(nil),并且值是不允许重复的
==========================Set========================== 添加数据
sadd key member1 [member2]
获取全部数据
smembers key
删除数据
srem key member1 [member2]
获取集合数据总量
scard key
判断集合中是否包含指定数据
sismember key member
业务场景一:========================================================== 每位用户首次使用今日头条时会设置3项爱好的内容,但是后期为了增加用户的活跃度、兴趣点,必须让用户 对其他信息类别逐渐产生兴趣,增加客户留存度,如何实现? 业务分析
1.系统分析出各个分类的最新或最热点信息条目并组织成set集合
2.随机挑选其中部分信息
3.配合用户关注信息分类中的热点信息组织成展示的全信息集合
解决方案
随机获取集合中指定数量的数据
srandmember key [count]
随机获取集合中的某个数据并将该数据移出集合
spop key [count]
Tips 1:
redis 应用于随机推荐类信息检索,例如热点歌单推荐,热点新闻推荐,热卖旅游线路,应用APP推荐, 大V推荐等
业务场景二:========================================================== 1.脉脉为了促进用户间的交流,保障业务成单率的提升,需要让每位用户拥有大量的好友,事实上职场新人不 具有更多的职场好友,如何快速为用户积累更多的好友?
2.新浪微博为了增加用户热度,提高用户留存性,需要微博用户在关注更多的人,以此获得更多的信息或热门 话题,如何提高用户关注他人的总量?
3.QQ新用户入网年龄越来越低,这些用户的朋友圈交际圈非常小,往往集中在一所学校甚至一个班级中,如何 帮助用户快速积累好友用户带来更多的活跃度?
4.美团外卖为了提升成单量,必须帮助用户挖掘美食需求,如何推荐给用户最适合自己的美食?
解决方案
求两个集合的交、并、差集
sinter key1 [key2]
sunion key1 [key2]
sdiff key1 [key2]
求两个集合的交、并、差集并存储到指定集合中
sinterstore destination key1 [key2]
sunionstore destination key1 [key2]
sdiffstore destination key1 [key2]
将指定数据从原始集合中移动到目标集合中
smove source destination member
set 类型数据操作的注意事项
1.set 类型不允许数据重复,如果添加的数据在 set 中已经存在,将只保留一份
2.set 虽然与hash的存储结构相同,但是无法启用hash中存储值的空间
具体实例
package com.ly.springboot_redis.pojo;
import java.io.Serializable;
public class Student implements Serializable {
private Integer stuid;
private String stuname;
private String stuhobby;
public Student(Integer stuid, String stuname, String stuhobby) {
this.stuid = stuid;
this.stuname = stuname;
this.stuhobby = stuhobby;
}
public Student() {
}
@Override
public String toString() {
return "Student{" +
"stuid=" + stuid +
", stuname='" + stuname + '\'' +
", stuhobby='" + stuhobby + '\'' +
'}';
}
public Integer getStuid() {
return stuid;
}
public void setStuid(Integer stuid) {
this.stuid = stuid;
}
public String getStuname() {
return stuname;
}
public void setStuname(String stuname) {
this.stuname = stuname;
}
public String getStuhobby() {
return stuhobby;
}
public void setStuhobby(String stuhobby) {
this.stuhobby = stuhobby;
}
}
package com.ly.springboot_redis.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.net.UnknownHostException;
@Configuration
public class JSonConfig {
@Bean
public RedisTemplate<Object,Object> jsonRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
//1.创建自定义模版类
RedisTemplate<Object,Object> template=new RedisTemplate<>();
//配置json类型的序列化工具
template.setKeySerializer(new StringRedisSerializer());//这样key会用字符串方式保存
template.setDefaultSerializer(new Jackson2JsonRedisSerializer<Object>(Object.class));
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}
测试类
package com.ly.springboot_redis;
import com.alibaba.fastjson.JSONObject;
import com.ly.springboot_redis.pojo.Student;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
@RunWith(SpringRunner.class)
@SpringBootTest
class SpringbootRedisApplicationTests {
//演示1(专用对象)
@Autowired
public RedisTemplate redisTemplate1;
//专用对象
@Autowired(required = false)
public StringRedisTemplate redisTemplate;
//演示3(自定义)
@Autowired
public RedisTemplate jsonRedisTemplate;
/**
* 测试stringRedisTemplate
* */
@Test
public void stringRedisTemplate(){
//1.key相关
Set<String> keys=redisTemplate.keys("*");
for (String key : keys) {
System.out.println(key);
}
//2.各种类型支持
redisTemplate.opsForValue();
redisTemplate.opsForList();
redisTemplate.opsForHash();
redisTemplate.opsForSet();
redisTemplate.opsForZSet();
//3.举例字符串
redisTemplate.opsForValue().set("name","蒋孝云");
String name = redisTemplate.opsForValue().get("name");
System.out.println(name);
//4.操作list列表
redisTemplate.opsForList().leftPush("mylist1","曹操");
redisTemplate.opsForList().leftPush("mylist1","曹植");
}
/**
* 测试自定义
* 定义配置类javaconfig,自定义序列化策略
* */
@Test
public void show3(){
//保存对象
Student stu=new Student(1,"小明","看书");
jsonRedisTemplate.opsForValue().set("stu",stu);
//获取对象
Object o = jsonRedisTemplate.opsForValue().get("stu");
String jsonString = JSONObject.toJSONString(o);
Student student = JSONObject.parseObject(jsonString, Student.class);
System.out.println(student);
Student stu1=new Student(2,"小红","听音乐");
Student stu2=new Student(2,"丹妮","听音乐");
Student stu3=new Student(2,"詹妮","听音乐");
List<Student> list= Arrays.asList(stu1,stu2,stu3);
jsonRedisTemplate.opsForValue().set("stus",list);
//必须接受Object,利用ObjectMapper对象转换,若强制转换会报错
Object data = jsonRedisTemplate.opsForValue().get("stus");
String datajson = JSONObject.toJSONString(data);
//将JSON转为List
List<Student> students=JSONObject.parseArray(datajson,Student.class);
System.out.println(students);
}
}