Redis 基础
# 简介
Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache, and message broker. 翻译为:Redis是一个开源的内存中的数据结构存储系统,它可以用作:数据库、缓存和消息中间件。
官网:https://redis.io (opens new window)
Redis是用C语言开发的一个开源的高性能键值对(key-value)数据库,官方提供的数据是可以达到100000+的QPS(每秒内查询次数)。它存储的value类型比较丰富,也被称为结构化的NoSql数据库。
NoSql(Not Only SQL),不仅仅是SQL,泛指非关系型数据库。NoSql数据库并不是要取代关系型数据库,而是关系型数据库的补充。
关系型数据库(RDBMS):表与表之间有关系,字段和字段也存在关系,将这些关系也存储了起来
- Mysql
- Oracle
- DB2
- SQLServer
非关系型数据库(NoSql):每个数据都是独立存在的.
- Redis--键值对
- Mongo db--文档型 user集合中{"username":"tom","age":18},{"username":"tom","sex":"男"}
- MemCached--键值对(过时了)
# Redis数据存储位置
- redis是一个内存数据库, 因此数据基本上都存在于内存当中
- 但是Redis会定时以追加或者快照的方式刷新到硬盘中.
- 由于redis是一个内存数据库, 所以读取写入的速度是非常快的, 所以经常被用来做数据, 页面等的缓存。
# Redis如何保证数据持久性
Redis保证数据持久性的方式有两种:
RDB持久化:RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘。也是默认的持久化方式,这种方式是就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为dump.rdb。
AOF持久化:一种更加高效的方式AOF,工作机制很简单,redis会将每一个收到的写命令都通过write函数追加到文件中。通俗的理解就是日志记录。然后在服务重启以后,会执行这些命令来恢复数据。
# windows 下让redis在后台运行
- 进入 DOS窗口
2. 在进入Redis的安装目录
3. 输入:redis-server --service-install redis.windows.conf --loglevel verbose ( 安装redis服务 )
4. 输入:redis-server --service-start ( 启动服务 )
5. 输入:redis-server --service-stop (停止服务)
启动指定的配置文件redis-server --service-start redis.windows-service.conf
# Redis数据类型
Redis存储的是key-value结构的数据,其中key是字符串类型,value有5种常用的数据类型:
- 字符串 string
- 哈希 hash
- 列表 list
- 集合 set
- 有序集合 sorted set / zset

- 字符串(string):普通字符串,常用
- 哈希(hash):适合存储对象
- 列表(list):按照插入顺序排序,可以有重复元素
- 集合(set):无序集合,没有重复元素
- 有序集合(sorted set / zset):集合中每个元素关联一个分数(score),根据分数升序排序,没有重复元素
# Redis常用指令
这里主要掌握操作String和Hash的即可,其他的了解
更多命令可以参考Redis中文网:https://www.redis.net.cn (opens new window)
# 字符串string操作命令
Redis 中字符串类型常用命令:
- SET key value 设置指定key的值
- GET key 获取指定key的值
- SETEX key seconds value 设置指定key的值,并将 key 的过期时间设为 seconds 秒
适用场景:验证码
- SETNX key value 只有在 key不存在时设置 key 的值
扩展:可以通过该命令设置分布式锁,防止覆盖key的值,该key使用完后可以释放掉分布式锁,也就是删掉这个key让其他人重新添加
- INCR key : 让key的值自增 +1
可以作为分布式id,往数据库中新增记录时候,可以让它维护主键 mysql中一张表只能存放1千万条数据,若要全国人口信息都放入表中的话怎么办?就需要将表进行拆分
- user_01,user_02,user_03...
- 插入记录每张表的id若用主键自增的话默认都是从1开始的,就会出现id相同的人.这时候就不能使用id自增了,可以使用其他方式维护主键值,例如redis中incr,插入一条数据的时候先获取下redis中指定key的值,获取好了之后将它的值自增下.
# 哈希hash操作命令
Redis hash 是一个string类型的 field 和 value 的映射表,hash特别适合用于存储对象,常用命令:
- HSET key field value 将哈希表 key 中的字段 field 的值设为 value
- HGET key field 获取存储在哈希表中指定字段的值
- HDEL key field 删除存储在哈希表中的指定字段
- HKEYS key 获取哈希表中所有字段
- HVALS key 获取哈希表中所有值
- HGETALL key 获取在哈希表中指定 key 的所有字段和值
# 列表list操作命令
Redis 列表是简单的字符串列表,按照插入顺序排序,常用命令:
LPUSH key value1 [value2] 将一个或多个值插入到列表头部
LRANGE key startIndex stopIndex 获取列表指定范围内的元素
RPOP key 移除并获取列表最后一个元素
LLEN key 获取列表长度
BRPOP key1 [key2 ] timeout 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列
表直到等待超时(秒)或发现可弹出元素为止
# 集合set操作命令
Redis set 是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据,常用命令:
- SADD key member1 [member2] 向集合添加一个或多个成员
- SMEMBERS key 返回集合中的所有成员
- SCARD key 获取集合的成员数
- SINTER key1 [key2] 返回给定所有集合的交集
- SUNION key1 [key2] 返回所有给定集合的并集
- SDIFF key1 [key2] 返回给定所有集合的差集
- SREM key member1 [member2] 移除集合中一个或多个成员
集合运算是比较强大: tom购买了电视机,电冰箱,洗衣机; jack买了洗衣机,空调. 这时候若用mysql去找他们交集商品的话会非常麻烦, 但是若使用redis就轻而易举了
# 有序集合sorted set操作命令
Redis sorted set 有序集合是 string 类型元素的集合,且不允许重复的成员。每个元素都会关联一个double类型的分数(score) 。redis正是通过分数来为集合中的成员进行从小到大排序。有序集合的成员是唯一的,但分数却可以重复。
常用命令:
- ZADD key score1 member1 [score2 member2] 向有序集合添加一个或多个成员,或者更新已存在成员的 分数
- ZRANGE key start stop [WITHSCORES] 通过索引区间返回有序集合中指定区间内的成员
- ZINCRBY key increment member 有序集合中对指定成员的分数加上增量 increment
- ZREM key member [member ...] 移除有序集合中的一个或多个成员
应用场景:各种排行榜
# 通用命令
Redis中的通用命令,主要是针对key进行操作的相关命令:
- KEYS pattern 查找所有符合给定模式( pattern)的 key
- EXISTS key 检查给定 key 是否存在
- TYPE key 返回 key 所储存的值的类型
- TTL key 返回给定 key 的剩余生存时间(TTL, time to live),以秒为单位
- 返回值-2:不存在
- 返回值-1:永不过时
- 正整数:剩余时间
- DEL key 该命令用于在 key 存在时删除 key
# Jedis
**简介:**Jedis 是 Redis 的 Java 版本的客户端实现。
maven坐标:
<dependencies>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
2
3
4
5
6
7
8
9
10
11
12
13
使用 Jedis 操作 Redis 的步骤:
- 获取连接
- 执行操作
- 关闭连接
示例代码:
package com.itheima.test;
import org.junit.Test;
import redis.clients.jedis.Jedis;
public class JedisTest {
@Test
public void test01(){
//1. 创建jedis并且连接到redis的服务端
Jedis jedis = new Jedis("192.168.206.128",6379);
//2. 存储数据
jedis.set("name","狗娃");
//3. 获取数据
System.out.println("获取到的数据:"+jedis.get("name"));
//4. 关闭连接
jedis.close();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Spring Data Redis
**介绍:**Spring Data Redis 是 Spring 的一部分,提供了在 Spring 应用中通过简单的配置就可以访问 Redis 服务,对 Redis 底层开发包进行了高度封装。在 Spring 项目中,可以使用Spring Data Redis来简化 Redis 操作。
官网:https://spring.io/projects/spring-data-redis (opens new window)
maven坐标:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>2.4.8</version>
</dependency>
2
3
4
5
Spring Boot提供了对应的Starter,maven坐标:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2
3
4
Spring Data Redis中提供了一个高度封装的类:RedisTemplate,针对 Jedis 客户端中大量api进行了归类封装,将同一类型操作封装为operation接口,具体分类如下:
- ValueOperations:简单K-V操作
- SetOperations:set类型数据操作
- ZSetOperations:zset类型数据操作
- HashOperations:针对hash类型的数据操作
- ListOperations:针对list类型的数据操作
# 使用方式
环境搭建
第一步:创建maven项目springdataredis_demo,配置pom.xml文件
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.5</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.4.5</version>
</plugin>
</plugins>
</build>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
第二步:编写启动类
package com.itheima;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class,args);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
第三步:配置application.yml
spring:
redis:
host: 192.168.206.128
port: 6379
# password: 有密码你才写
database: 0 #redis默认有16个数据库, 操作的数据库是哪个
jedis:
pool:
max-active: 10 #最大链接数,连接池中最多有10个
max-idle: 5 # 最大空闲数
min-idle: 1 #最小空闲数
#举个例子: 连接池初始化3个链接, 客户拿走2个链接,空闲1个,达到最小的空闲数,必须马上增加
max-wait: 1ms #连接池最大阻塞等待时间
2
3
4
5
6
7
8
9
10
11
12
13
解释说明:
spring.redis.database:指定使用Redis的哪个数据库,Redis服务启动后默认有16个数据库,编号分别是从0到15。可以通过修改Redis配置文件来指定数据库的数量。
第四步:
springdata_redis默认帮我们创建的RedisTemplate对象是使用jdk的序列号器帮我们键与值存储到redis中,而jdk的序列号器对键与值是采用二进制的方式存储的,所以我们会看到乱码的情况。如果我们需要看得懂,那么需要修改redistemplate使用的序列号器才行。
提供配置类
package com.itheima.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.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class MyRedisAutoConfig {
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
template.setKeySerializer(new StringRedisSerializer()); //key的序列号器
template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); //值序列号器
return template;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
由于值序列号器选择了json的序列化,所以需要添加json的依赖添加依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.5</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.11.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.11.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.4.5</version>
</plugin>
</plugins>
</build>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
解释说明:
当前配置类不是必须的,因为 Spring Boot 框架会自动装配 RedisTemplate 对象,但是默认的key序列化器为JdkSerializationRedisSerializer,导致我们存到Redis中后的数据和原始数据有差别
第五步:提供测试类
package com.itheima.test;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.*;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@SpringBootTest
public class RedisTemplateTest {
@Autowired
private RedisTemplate<String,String> redisTemplate;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 操作示例
package com.itheima.test;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.connection.DataType;
import org.springframework.data.redis.core.*;
import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@SpringBootTest
public class TestRedisTemplate {
@Autowired
RedisTemplate redisTemplate;
@Test
public void testValue() {
ValueOperations valueOperations = redisTemplate.opsForValue();
valueOperations.set("hello","spring data redis");
Object value = valueOperations.get("hello");
System.out.println(value);
HashMap<String, Object> map = new HashMap<>();
map.put("username","tom");
map.put("age",18);
valueOperations.set("mm",map);
value = valueOperations.get("mm");
System.out.println(value);
//设置过期时间
valueOperations.set("hi1","我1分钟过期", Duration.ofMinutes(1));
valueOperations.set("hi2","我1分钟过期", 1, TimeUnit.MINUTES);
//setnx
Boolean flag = valueOperations.setIfAbsent("id", 1);
System.out.println(flag);//true
flag = valueOperations.setIfAbsent("id", 1);
System.out.println(flag);//false
}
@Test
public void testHash() {
HashOperations hashOperations = redisTemplate.opsForHash();
hashOperations.put("user1","username","tom");
hashOperations.put("user1","age",18);
Object username = hashOperations.get("user1", "username");
System.out.println(username);
Set keySet = hashOperations.keys("user1");
System.out.println(keySet);
List valueList = hashOperations.values("user1");
System.out.println(valueList);
}
@Test
public void testList() {
ListOperations listOperations = redisTemplate.opsForList();
listOperations.leftPushAll("list1","a","b","c");
Long size = listOperations.size("list1");
System.out.println(size);//cba
List list = listOperations.range("list1", 0, -1);
System.out.println(list);//3
Object element = listOperations.rightPop("list1");
System.out.println(element);//a
}
@Test
public void testSet() {
SetOperations setOperations = redisTemplate.opsForSet();
setOperations.add("set1","a","b","c");
Set set = setOperations.members("set1");
System.out.println(set);
Long size = setOperations.size("set1");
System.out.println(size);//3
setOperations.remove("set1", "c");
size = setOperations.size("set1");
System.out.println(size);//2
}
@Test
public void testZset() {
ZSetOperations zSetOperations = redisTemplate.opsForZSet();
zSetOperations.add("166java","tom",88);
zSetOperations.add("166java","jack",69);
zSetOperations.add("166java","rose",100);
//获取某个元素的得分
Double tomScore = zSetOperations.score("166java", "tom");
System.out.println(tomScore);//88
//将tom的分数加10分
zSetOperations.incrementScore("166java","tom",10);
tomScore = zSetOperations.score("166java", "tom");
System.out.println(tomScore);//98
System.out.println("---------");
Set set = zSetOperations.range("166java", 0, -1);
for (Object member : set) {
//获取每个元素的得分
System.out.println(member+":"+zSetOperations.score("166java", member));
}
}
//通用命令的操作
@Test
public void testCommons() {
//判断元素是否存在
Boolean result = redisTemplate.hasKey("user1");
System.out.println(result);
//判断元素的类型
DataType type = redisTemplate.type("166java");
System.out.println(type);
//删除元素
Boolean flag = redisTemplate.delete("166java");
System.out.println(flag);
//keys 通配符
Set set = redisTemplate.keys("li*");
System.out.println(set);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
Redis基础课程讲义.pdf (opens new window)
# Docker安装redis
拉取redis镜像
docker pull redis
创建挂载目录
mkdir -p /usr/soft/docker-data/redis/data
cd /usr/soft/docker-data/redis
touch redis.conf
2
3
启动容器
docker run \
--restart=always \
--log-opt max-size=100m \
--log-opt max-file=2 \
-p 6379:6379 \
--name myredis \
-v /usr/local/docker/redis/redis.conf:/etc/redis/redis.conf \
-v /usr/local/docker/redis/data:/data \
-d redis redis-server /etc/redis/redis.conf \
--appendonly yes \
--requirepass root
2
3
4
5
6
7
8
9
10
11
--restart=always总是开机启动--log是日志方面的-p 6379:6379将6379端口挂载出去--name给这个容器取一个名字-v数据卷挂载- /home/redis/myredis/myredis.conf:/etc/redis/redis.conf这里是将 liunx 路径下的myredis.conf 和redis下的redis.conf 挂载在一起。- /home/redis/myredis/data:/data这个同上-d redis表示后台启动redisredis-server /etc/redis/redis.conf以配置文件启动redis,加载容器内的conf文件,最终找到的是挂载的目录 /etc/redis/redis.conf 也就是liunx下的/home/redis/myredis/myredis.conf–appendonly yes开启redis 持久化–requirepass 000415设置密码,如果是通过docker 容器内部连接的话,就随意,可设可不设。但是如果想向外开放的话,一定要设置