1. 安装 Redis
1.1 安装
# Redis 是 c 语言编写,需要安装依赖库
yum install -y gcc tcl
# 上传压缩包后解压
tar -xzf redis-6.2.6.tar.gz
# 进入 Redis 目录
cd redis-6.2.6
# 编译安装
make && make install
1.2 启动
1.2.1 指定配置文件启动
# 允许访问的地址,默认是 127.0.0.1,会导致只能在本地访问。修改为 0.0.0.0 则可以在任意 IP 访问
bind 0.0.0.0
# 守护进程,修改为yes后即可后台运行
daemonize yes
# 密码,设置后访问 Redis 必须输入密码
requirepass 123321
# 监听的端口
port 6379
# 工作目录,默认是当前目录,也就是运行 redis-server 时的命令,日志、持久化等文件会保存在这个目录
dir .
# 数据库数量,设置为 1,代表只使用 1 个库,默认有 16 个库,编号 0~15
databases 1
# 设置 redis 能够使用的最大内存
maxmemory 512mb
# 日志文件,默认为空,不记录日志,可以指定日志文件名
logfile "redis.log"
# 启动
redis-server redis.conf
1.2.2 开机自启
# 新建一个系统服务文件,文件内容见下方
vi /etc/systemd/system/redis.service
# 重载系统服务
systemctl daemon-reload
[Unit]
Description=redis-server
After=network.target
[Service]
Type=forking
ExecStart=/usr/local/bin/redis-server /usr/local/redis-6.2.6/redis.conf
PrivateTmp=true
[Install]
WantedBy=multi-user.target
# 启动
systemctl start redis
# 停止
systemctl stop redis
# 重启
systemctl restart redis
# 查看状态
systemctl status redis
2. Redis 常见命令
2.1 通用命令
通用指令是部分数据类型的,都可以使用的指令,常见的有:
KEYS:查看符合模板的所有 key
DEL:删除一个指定的 key
EXISTS:判断 key 是否存在
EXPIRE:给一个 key 设置有效期,有效期到期时该 key 会被自动删除
TTL:查看一个KEY的剩余有效期
2.2 String 类型
String 类型,也就是字符串类型,是 Redis 中最简单的存储类型。其 value 是字符串,不过根据字符串的格式不同,又可以分为3类:
- string:普通字符串
- int:整数类型,可以做自增、自减操作
- float:浮点类型,可以做自增、自减操作
不管是哪种格式,底层都是字节数组形式存储,只不过是编码方式不同。字符串类型的最大空间不能超过 512m
SET:添加或者修改已经存在的一个 String 类型的键值对
GET:根据 key 获取 String 类型的 value
MSET:批量添加多个String类型的键值对
MGET:根据多个 key 获取多个 String 类型的 value
INCR:让一个整型的 key 自增 1
INCRBY:让一个整型的 key 自增并指定步长,例如:incrby num 2 让 num 值自增 2
INCRBYFLOAT:让一个浮点类型的数字自增并指定步长
SETNX:添加一个 String 类型的键值对,前提是这个 key 不存在,否则不执行
SETEX:添加一个 String 类型的键值对,并且指定有效期
2.3 Hash 类型
Hash 类型,也叫散列,其 value 是一个无序字典,类似于 Java 中的 HashMap 结构
String 结构是将对象序列化为 JSON 字符串后存储,当需要修改对象某个字段时很不方便
Hash 结构可以将对象中的每个字段独立存储,可以针对单个字段做 CRUD
HSET key field value:添加或者修改 hash 类型 key 的 field 的值
HGET key field:获取一个 hash 类型 key 的 field 的值
HMSET:批量添加多个 hash 类型 key 的 field 的值
HMGET:批量获取多个 hash 类型 key 的 field 的值
HGETALL:获取一个 hash 类型的 key 中的所有的 field 和 value
HKEYS:获取一个 hash 类型的 key 中的所有的 field
HVALS:获取一个 hash 类型的 key 中的所有的 value
HINCRBY:让一个 hash 类型 key 的字段值自增并指定步长
HSETNX:添加一个 hash 类型的 key 的 field 值,前提是这个 field 不存在,否则不执
2.4 List 类型
Redis 中的 List 类型与 Java 中的 LinkedList 类似,可以看做是一个双向链表结构。既可以支持正向检索和也可以支持反向检索,特征也与 LinkedList 类似:
- 有序
- 元素可以重复
- 插入和删除快
- 查询速度一般
常用来存储一个有序数据,例如:朋友圈点赞列表,评论列表等
LPUSH key element ... :向列表左侧插入一个或多个元素
LPOP key:移除并返回列表左侧的第一个元素,没有则返回 nil
RPUSH key element ... :向列表右侧插入一个或多个元素
RPOP key:移除并返回列表右侧的第一个元素
LRANGE key star end:返回一段角标范围内的所有元素
BLPOP 和 BRPOP:与 LPOP 和 RPOP 类似,只不过在没有元素时等待指定时间,而不是直接返回 nil
如何利用 List 结构模拟一个栈
- 入口和出口在同一边
如何利用 List 结构模拟一个队列
- 入口和出口在不同边
如何利用 List 结构模拟一个阻塞队列
- 入口和出口在不同边出队时
-
2.5 Set 类型
Redis 的 Set 结构与 Java 中的 HashSet 类似,可以看做是一个 value 为 null 的 HashMap。因为也是一个 hash 表,因此具备与 HashSet 类似的特征:
无序
- 元素不可重复
- 查找快
- 支持交集、并集、差集等功能 ``` SADD key member … :向 set 中添加一个或多个元素
SREM key member … : 移除 set 中的指定元素
SCARD key: 返回 set 中元素的个数
SISMEMBER key member:判断一个元素是否存在于 set 中
SMEMBERS:获取 set 中的所有元素
SINTER key1 key2 … :求 key1 与 key2 的交集
SDIFF key1 key2 … :求 key1 与 key2 的差集
SUNION key1 key2 ..:求 key1 和 key2 的并集
<a name="WukA4"></a>
## 2.6 SortedSet 类型
Redis 的 SortedSet 是一个可排序的set集合,与 Java 中的 TreeSet 有些类似,但底层数据结构却差别很大。SortedSet 中的每一个元素都带有一个 score 属性,可以基于 score 属性对元素排序,底层的实现是一个跳表(SkipList)+ hash 表。
SortedSet 具备下列特性:
- 可排序
- 元素不重复
- 查询速度快
- 因为 SortedSet 的可排序特性,经常被用来实现排行榜这样的功能
ZADD key score member:添加一个或多个元素到 sorted set ,如果已经存在则更新其 score 值
ZREM key member:删除 sorted set 中的一个指定元素
ZSCORE key member : 获取 sorted set 中的指定元素的 score 值
ZRANK key member:获取 sorted set 中的指定元素的排名
ZCARD key:获取 sorted set 中的元素个数
ZCOUNT key min max:统计 score 值在给定范围内的所有元素的个数
ZINCRBY key increment member:让 sorted set 中的指定元素自增,步长为指定的 increment 值
ZRANGE key min max:按照 score 排序后,获取指定排名范围内的元素
ZRANGEBYSCORE key min max:按照 score 排序后,获取指定 score 范围内的元素
ZDIFF、ZINTER、ZUNION:求差集、交集、并集
注意:所有的排名默认都是升序,如果要降序则在命令的 Z 后面添加 REV 即可
<a name="yA3zb"></a>
# 3. SpringDataRedis
<a name="P48mM"></a>
## 3.1 介绍
SpringData 是 Spring 中数据操作的模块,包含对各种数据库的集成,其中对 Redis 的集成模块就叫做 SpringDataRedis,官网地址是[https://spring.io/projects/spring-data-redis](https://spring.io/projects/spring-data-redis)
- 提供了对不同 Redis 客户端的整合(Lettuce 和 Jedis)
- 提供了 RedisTemplate 统一 API 来操作 Redis
- 支持 Redis 的发布订阅模型
- 支持 Redis 哨兵和 Redis 集群
- 支持基于 Lettuce 的响应式编程
- 支持基于 JDK、JSON、字符串、Spring 对象的数据序列化及反序列化
- 支持基于 Redis 的 JDKCollection 实现
SpringDataRedis 中提供了 RedisTemplate 工具类,其中封装了各种对 Redis 的操作。并且将不同数据类型的操作 API 封装到了不同的类型中
| API | 返回值类型 | 说明 |
| --- | --- | --- |
| **redisTemplate**.opsForValue() | ValueOperations | 操作 String 类型数据 |
| **redisTemplate**.opsForHash() | HashOperations | 操作 Hash 类型数据 |
| **redisTemplate**.opsForList() | ListOperations | 操作 List 类型数据 |
| **redisTemplate**.opsForSet() | SetOperations | 操作 Set 类型数据 |
| **redisTemplate**.opsForZSet() | ZSetOperations | 操作 SortedSet 类型数据 |
| **redisTemplate** | | 通用的命令 |
<a name="XylVM"></a>
## 3.2 序列化方式
<a name="oWmgF"></a>
### 3.2.1 JDK 序列化方式
因为默认使用的 `JdkSerializationRedisSerializer`序列化方式,所以这里的 key 和 value 都变成了如下格式
```java
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {
private Long id;
private String name;
}
@SpringBootApplication
public class SpringDataRedisApplication implements ApplicationRunner {
@Autowired
private RedisTemplate redisTemplate;
public static void main(String[] args) {
SpringApplication.run(SpringDataRedisApplication.class, args);
}
@Override
public void run(ApplicationArguments args) throws Exception {
// 存储字符串对象
redisTemplate.opsForValue().set("name", "张三");
System.out.println(redisTemplate.opsForValue().get("name"));
// 存储实体类型
redisTemplate.opsForValue().set("user:1", new User(1L, "张三"));
System.out.println(redisTemplate.opsForValue().get("user:1"));
}
}
127.0.0.1:6379> keys *
1) "\xac\xed\x00\x05t\x00\x06user:1"
2) "\xac\xed\x00\x05t\x00\x04name"
127.0.0.1:6379> get \xac\xed\x00\x05t\x00\x04name
(nil)
127.0.0.1:6379> get "\xac\xed\x00\x05t\x00\x04name"
"\xac\xed\x00\x05t\x00\x06\xe5\xbc\xa0\xe4\xb8\x89"
127.0.0.1:6379> get "\xac\xed\x00\x05t\x00\x06user:1"
"\xac\xed\x00\x05sr\x009org.masteryourself.tutorial.spring.data.redis.entity.User,&\xf2t\x9f\x94\xc3)\x02\x00\x02L\x00\x02idt\x00\x10Ljava/lang/Long;L\x00\x04namet\x00\x12Ljava/lang/String;xpsr\x00\x0ejava.lang.Long;\x8b\xe4\x90\xcc\x8f#\xdf\x02\x00\x01J\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x00\x00\x00\x00\x00\x01t\x00\x06\xe5\xbc\xa0\xe4\xb8\x89"
3.2.2 指定序列化格式
为了在反序列化时知道对象的类型,JSON 序列化器会将类的 class 类型写入 json 结果中,存入 Redis,会带来额外的内存开销
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
// 创建Template
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
// 设置连接工厂
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 设置序列化工具
GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
// key 和 hashKey 采用 string 序列化
redisTemplate.setKeySerializer(RedisSerializer.string());
redisTemplate.setHashKeySerializer(RedisSerializer.string());
// value 和 hashValue采用 JSON 序列化
redisTemplate.setValueSerializer(jsonRedisSerializer);
redisTemplate.setHashValueSerializer(jsonRedisSerializer);
return redisTemplate;
}
}
@SpringBootApplication
public class SpringDataRedisApplication implements ApplicationRunner {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public static void main(String[] args) {
SpringApplication.run(SpringDataRedisApplication.class, args);
}
@Override
public void run(ApplicationArguments args) throws Exception {
// 存储字符串对象
redisTemplate.opsForValue().set("name", "张三");
String str = (String) redisTemplate.opsForValue().get("name");
System.out.println(str);
// 存储实体类型
redisTemplate.opsForValue().set("user:1", new User(1L, "张三"));
User user = (User) redisTemplate.opsForValue().get("user:1");
System.out.println(user);
}
}
127.0.0.1:6379> keys *
1) "user:1"
2) "name"
127.0.0.1:6379> get name
"\"\xe5\xbc\xa0\xe4\xb8\x89\""
127.0.0.1:6379> get user:1
"{\"@class\":\"org.masteryourself.tutorial.spring.data.redis.entity.User\",\"id\":1,\"name\":\"\xe5\xbc\xa0\xe4\xb8\x89\"}"
3.2.3 StringRedisTemplate
Spring 默认提供了一个 StringRedisTemplate
类,它的 key 和 value 的序列化方式默认就是 String 方式
@SpringBootApplication
public class SpringDataRedisApplication implements ApplicationRunner {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private StringRedisTemplate stringRedisTemplate;
public static void main(String[] args) {
SpringApplication.run(SpringDataRedisApplication.class, args);
}
@Override
public void run(ApplicationArguments args) throws Exception {
// 存储字符串对象
stringRedisTemplate.opsForValue().set("name", "张三");
String str = stringRedisTemplate.opsForValue().get("name");
System.out.println(str);
// 存储实体类型
ObjectMapper mapper = new ObjectMapper();
User userWrite = new User(1L, "张三");
stringRedisTemplate.opsForValue().set("user:1", mapper.writeValueAsString(userWrite));
String jsonStr = stringRedisTemplate.opsForValue().get("user:1");
User readUser = mapper.readValue(jsonStr, User.class);
System.out.println(readUser);
}
}
127.0.0.1:6379> keys *
1) "user:1"
2) "name"
127.0.0.1:6379> get name
"\xe5\xbc\xa0\xe4\xb8\x89"
127.0.0.1:6379> get user:1
"{\"id\":1,\"name\":\"\xe5\xbc\xa0\xe4\xb8\x89\"}"