简介
官方文档:Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache and message broker. It supports data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs, geospatial indexes with radius queries and streams. Redis has built-in replication, Lua scripting, LRU eviction, transactions and different levels of on-disk persistence, and provides high availability via Redis Sentinel and automatic partitioning with Redis Cluster.
翻译:Redis 是 一个开源(BSD 许可),内存数据结构存储,用作数据库,缓存和消息代理。它支持数据结构,如字符串,散列,列表,集合,带有范围查询的排序集,位图,超级日志,具有半径查询和流的地理空间索引。
Redis 具有内置复制,Lua 脚本,LRU 回收,事务和不同级别的磁盘持久性,同时通过 Redis Sentinel 提供高可用性,通过 Redis Cluster 提供自动分区。
特点
- Redis 基于内存,并支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用
- Redis 不仅支持简单的 key-value 类型的数据,同时还提供 list,set,zset,hash 等数据结构的存储
- Redis 支持数据的备份,即 master-slave 模式的数据备份
优势
- 性能极高 – Redis 能读的速度是 110000 次 /s ,写的速度是 81000 次 /s
- 丰富的数据类型 – Redis 支持二进制案例的 Strings,Lists,Hashes,Sets 及 Ordered Sets 数据类型操作
- 原子 – Redis 的所有操作都是原子性的,同时 Redis 还支持对几个操作全并后的原子性执行操作
- 丰富的特性 – Redis 还支持 publish/subscribe,通知,key 过期等等特性
应用场景
Redis 可以在很多场景下使用,比如:
- 计数器
- 消息队列
- 排行榜
- 秒杀系统
- 验证码
- 分布式锁
- 热数据缓存
下载与安装
Redis 的版本分为稳定版和非稳定版,其根据次版本号(即第一个小数点后的数字)的奇偶进行区分:
- 若次版本号为偶数,则为稳定版本,如 2.6、2.8、3.0
- 若次版本号为奇数,则非稳定版本,如 2.7、2.9、3.1
下载
我们从 Redis 官网下载地址下载稳定的 Redis 6.2.6 版本。
安装
环境准备
Redis 基于 C 语言编写的,其依赖于 gcc :
1 | yum install -y gcc tcl |
解压
1 | tar -xzf redis-6.2.6.tar.gz |
编译安装
1 | cd redis-6.2.6 |
编译安装完成后,将在/usr/local/bin
目录下生成以下多个脚本(下面为部分):
redis-cli
:Redis 客户端启动脚本redis-server
:Redis 服务端启动脚本redis-sentinel
:Redis 哨兵启动脚本
命令
下面为一些常用命令:
启动服务器
通过以下命令可以启动 Redis:1
redis-server
当然,以上命令使用的是默认的配置启动的 Redis,我们也可以指定配置文件进行启动:1
redis-server /data/software/redis-6.2.6/redis.conf
客户端测试
通过 Redis 客户端连接 Redis 服务器,查看 Redis 是否启动,这使用以下命令:
1 | redis-cli |
执行以上命令将打开以下终端:
1 | redis 127.0.0.1:6379> |
127.0.0.1 是本机 IP ,6379 是 Redis 服务端口,之后我们输入 PING 命令:
1 | redis 127.0.0.1:6379> ping |
出现PONG
则说明我们已经成功安装了 Redis.
开机自启
若想实现 Redis 开机自启,需要进行一些配置。
配置
首先,新建一个系统服务文件:
1 | vi /etc/systemd/system/redis.service |
写入以下内容:
1 | [Unit] |
然后重载系统服务:
1 | systemctl daemon-reload |
系统命令控制
配置完成后,就可以用下面这组命令来操作 Redis 了:
命令 | 说明 |
---|---|
systemctl start redis |
启动 |
systemctl stop redis |
停止 |
systemctl restart redis |
重启 |
systemctl status redis |
状态查看 |
systemctl enable redis |
开机自启 |
常用配置
Redis 的配置文件位于安装目录下,文件名为redis.conf
,通过修改该文件内容可进行自定义配置,启动 Redis 时会使用这些配置。
下面只介绍几个常用的配置:
bind 127.0.0.1 ::1
:默认情况下该配置只能接受本机的访问请求(测试阶段使用#
注释掉即可无限制接受任何 ip 地址的访问),生产环境请使用应用服务器的地址。若开启了protected-mode
且没有设置密码,则 Redis 只接受本机访问。protected-mode yes
:保护模式,开启时需要设置 bind ip 或者密码。关闭时外部 ip 可以直接访问port 6379
:Redis 服务端口号daemonize no
:Redis 默认不是以守护进程(即不会常驻后台)的方式运行,可修改值为yes
以启用守护进程tcp-backlog 511
:等待最大队列数,此处设置无效,默认为 128 ,需要修改另一处配置文件timeout 0
:一个空闲的客户端维持多少秒会关闭, 0 代表永不关闭tcp-keepalive 300
:对访问客户端的心跳检测,每隔 300 秒检测一次pidfile
:当 Redis 以守护进程方式运行时,Redis 默认会把 pid 写入/var/run/redis.pid
文件,可以通过 pidfile 指定自定义文件位置
基本命令
Redis 命令大小写均可,可是作为中国人,总觉得大写有点变扭,无法像看简体繁体一样直接理解其意,因此个人更习惯使用小写。
下表显示了一些 Redis 的常用命令:
命令 | 说明 |
---|---|
redis-server |
以默认配置启动 Redis 服务器 |
redis-server [redis.conf] |
指定配置文件启动 Redis 服务器 |
redis-cli |
启动客户端连接本地 Redis 服务器 |
redis-cli -h <host> -p <port> -a <password> |
启动客户端连接远程 Redis 服务器(指定服务器 IP 端口和密码) |
ping |
连接服务器后使用该命令检测 Redis 服务是否启动(成功返回PONG ) |
select <index> |
选择某个库 |
keys * |
查询当前库的所有键,* 可以使用其他通配符代替 |
exitsts <key> |
判断某个键是否存在 |
type <key> |
判断键的类型 |
del <key> |
删除某个键 |
expire <key> <second> |
为键值设置过期(删除)时间,单位秒 |
ttl <key> |
查看键还有多少秒过期,-1 表示永不过期,-2 表示已过期 |
dbsize |
查看当前数据库的 key 的数量 |
flushdb |
清空当前库数据 |
flushall |
通杀全部库数据 |
基本组成
我们知道 Redis 中存放了数据,那么自然就会有一个疑问:这些数据在 Redis 服务器内部是怎么组成的呢?
简而言之,Redis 服务器中有数据库,数据库中有键空间,键空间中存放了真正的数据。
服务器中的数据库
Redis 服务器将所有数据库都保存在服务器状态 redis.h/redisServer 结构的 db 数组中:1
2
3
4
5
6
7
8struct redisServer {
// ...
// 一个数组,保存着服务器中的所有数据库,每个项都是一个 redis.h/redisDb 结构,每个 redisDb 结构代表一个数据库
redisDb *db;
// 服务器的数据库数量
int dbnum;
// ...
}
在初始化服务器时,程序会根据服务器状态的 dbnum 属性来决定应该创建多少个数据库,此属性值由服务器配置的 database 决定,默认为 16,因此默认情况下 Redis 服务器会创建 16 个数据库,如下图所示:
数据库中的键空间
Redis 是一个键值对(key-value pair)数据库服务器,服务器中的每个数据库都由一个 redis.h/redisDb 结构表示,其中,redisDb 结构的 dict 字典保存了数据库中的所有键值对,我们将这个字典称为键空间(keyspace):1
2
3
4
5
6typedef struct redisDb {
// ...
// 数据库键空间,保存着数据库中的所有键值对
dict *dict;
// ...
} redisDb;
键空间和用户所见的数据库是直接对应的:
- 键空间的键也就是数据库的键,每个键都是一个字符串对象
- 键空间的值也就是数据库的值,每个值可以是字符串对象、列表对象、哈希表对象、集合对象和有序集合对象中的任意一种 Redis 对象
举个例子,如果我们在空白的数据库中执行以下命令:1
2
3
4
5
6
7
8
9
10127.0.0.1:6379> set msg "hello world"
OK
127.0.0.1:6379> rpush alphabet "a" "b" "c"
(integer) 3
127.0.0.1:6379> hset book name "Redis in Action"
(integer) 1
127.0.0.1:6379> hset book author "Josiah L. Carlson"
(integer) 1
127.0.0.1:6379> hset book publisher "Manning"
(integer) 1
那么在这些命令执行之后,数据库的键空间将会是下图展示的样子:
因为数据库的键空间是一个字典,所以所有针对数据库的操作,比如添加一个键值对到数据库,或者从数据库中删除一个键值对,又或者在数据库中获取某个键值对等,实际上都是通过对键空间字典进行操作来实现的。
键空间的对象类型
既然 Redis 中的键和值都是由对象定义的,那么,Redis 中存在哪些对象呢?
Redis 支持的对象(亦可称为数据类型),总共可以分为五类:
- String(字符串)
- List(列表)
- Set(无序集合)
- Sorted Set(有序集合)
- Hash(哈希表)
String 类型
String 是 Redis 最基本的类型。
特点
String 类型的其特点如下:
- 一个 key 对应一个 value,相当于 Java 的
Map<String,String>
- 该类型是二进制安全的,所以可以包含任何数据(如 jpg 图片或者序列化的对象)
- 一个 Redis 中字符串 value 最大容量为 512M
命令
String 类型的相关命令:
get <key>
:获取指定键的值set <key> <value>
:设置键与值append <key> <value>
:追加指定值到原值末尾strlen <key>
:获取键的长度setnx <key> <value>
:设置完键值后不可被覆盖incr <key>
:将 key 中存储的数字值加 1,只能对数字值操作decr <key>
:将 key 中存储的数字值减 1,只能对数字值操作incrby/decrby <key> <步长>
:将 key 中存储的数字加/减指定步长mset <key1> <value1> <key2> <value2>
:同时设置多个键值对mget <key1> <value1> <key2> <value2>
:同时获取多个键值对msetnx <key1> <value1> <key2> <value2>
:同时设置多个键值对,不可被覆盖get range <key> <起始位置> <结束位置>
:获得值的范围,类似 Java 的substringsetrange <key> <起始位置> value
:从起始位置以value
值代替setex <key> <过期时间> <value>
:设置键值的同时,设置过期时间,单位秒psetex <key> <过期时间> <value>
:这个命令和setex
命令相似,但它以毫秒为单位设置 key 的生存时间,而不是像setex
命令那样,以秒为单位getset <key> <value>
:以新换旧,设置新值同时获得新值
业务场景
例如小破站某热点视频当前观看用户数,点赞、投币、收藏数,可以选择 String 类型。
在 Redis 中为视频设定视频信息,以视频主键和属性值作为 key,后台设定定时刷新策略即可:1
2
3
4
5
6
7
8
9video_id_BV1CJ411m7Gc_audiences
88888
video_id_BV1CJ411m7Gc_likes
6164
eg:
video_id_BV1CJ411m7Gc_coins
12222
video_id_BV1CJ411m7Gc_collections
666
List 类型
List 列表的特点如下:
- 单键多值,相当于 Java 中的
Map<String,List<String>
- 底层是双向循环链表
- 作为简单的字符串集合,按照插入顺序排序
- List 列表可以作为栈或队列使用,因此可添加一个元素到列表的头部(左边)或者尾部(右边)
- 对两端的操作性能很高,通过索引下标的操作中间的节点性能会变差;
- 最多可以包含 $2^{32}$ - 1个元素 (即 4294967295 )
下面为其相关命令:
lpush/rpush <key> <value1> <value2>
:从左边/右边插入一个或多个值到列表头部lpop/rpop <key>
:从左边/右边吐出一个值,值在键在,值空键亡rpoplpush <key1> <key2>
:从<key1>
列表右边吐出一个值,插到<key2>
列表右边lrange <key> <start> <end>
:按照索引下标获得元素(从左到右)lindex <key> <index>
:按照索引下标获得元素(从左到右)llen <key>
:获得列表长度linsert <key> before/after <pivot> <value>
:在指定列表的指定值前面或后面插入新值lrem <key> <n> <value>
:删除n个value(可以有多个相同的value,n为正数代表从左边删除,负数则从右边,0 代表删除所有 )
Set 类型
Set 集合特点如下:
- String 类型的无序集合,相当于 Java 中的
Map<String,Set<String>>
- 集合成员唯一,这意味着集合中不能出现重复的数据
- 该集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是
O(1)
- 每个集合可存储 $2^{32}$ - 1 个元素(4294967295)
下面为其相关命令:
sadd <key> <member1> <member2>
:向集合添加一个或多个成员,重复成员将被省略smembers <key>
:查看集合中的所有成员sismember <key> <member>
:判断 member 元素是否为集合中的内容,有返回 1,无返回 0scard <key>
:返回该集合的个数srem <key> <member1> <member2>
:删除集合中的成员,可同时删除多个spop <key>
:随机吐出集合中的一个成员并显示srandmember <key> <n>
:随机从该集合中取出 n 个值,不会从集合中删除sinter <key1> <key2>
:返回两个集合的交集sunion <keyl> <key2>
:返回两个集合的并集sdiff <key1> <key2>
:返回两个集合的差集,集合先后顺序不同结果不同
Sorted Set 类型(有序集合)
Sorted Set 集合特点如下:
- 也是 String 类型元素的集合,但其有顺序
- 集合成员唯一,这意味着集合中不能出现重复的数据
- 不同的是每个元素都会关联一个 double 类型的分数
(score)
,Redis 正是通过分数来为集合中的成员进行从小到大的排序 - 有序集合的成员是唯一的,但分数
(score)
却可以重复。 - 该集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。
- 每个集合可存储 $2^{32}$ - 1 个元素(4294967295)
下面为其相关命令:
zadd <key> <score1> <member1> <score2> <member2>
:向有序集合按分数添加一个或多个成员,或者更新已存在成员的分数zrange key <start> <stop> [withscores]
:通过索引区间返回有序集合成指定区间内的成员(可选显示分数)zrangebyscore key min max [withscores]
:通过分数从小到大返回有序集合指定区间内的成员zrevrangebyscore key max min [withscores]
:通过分数从大到小返回有序集合指定区间内的成员zincrby <key> <increment> <member>
:有序集合中对指定成员的分数加上增量 incrementzrem <key> <member1> <member2>
:移除有序集合中的一个或多个成员zcount <key> <min> <max>
:计算在有序集合中指定区间分数的成员数zrank <key> <member>
:返回有序集合中指定成员的索引排名
Hash 类型
Hash 散列表特点如下:
- String 类型的 field 和 value 的映射表,相当于 Java 中的
Map<String,Map<String,String>
,键是字符串,值是另一个映射 - Hash 特别适合用于存储对象
- 每个 Hash 散列表可以存储 $2^{32}$ - 1 个键值对(40多亿)。
下面为其相关命令:
hset key <field> <value>
:将哈希表 key 中的字段 field 的值设为 valuehget key <field>
:获取存储在哈希表中指定字段的值hmset key <field1> <value1> <fields2> <value2>
:同时将多个 field-value (域-值)对设置到哈希表 key 中hexists key <field
>:查看哈希表 key 中,给定 field 是否存在hkeys <key>
:列出该哈希表中所有的 fieldhincrby <key> <field>
:为哈希表 key 中的 field 的值加上增量hsetnx <key> <field> <value>
:为哈希表 key 追加一个 field 字段,其值设置为 value,仅当 field 不存在时
Java API
作为 Java 开发工程师,肯定想通过 Java 连接 Redis ,此时就需要用到一些常用的依赖包了:
- Jedis 或 Lettuce
- Spring Data Redis
- Redission
Jedis
不推荐使用了。
Spring Data Redis
Spring Data Redis 是 Spring Data 家族的一部分。
Spring Boot 提供了对 Redis 集成的组件包spring-boot-data-redis
,它依赖于 spring-data-redis 和 lettuce。
Spring Boot 1.0 默认使用的是 Jedis 客户端,2.0 替换成了 Lettuce。
下面对几个概念说明一下:
- Spring Data:是 Spring 框架中的一个主要项目,目的是为了简化构建基于 Spring 框架应用的数据访问,包括非关系数据库、 Map-Reduce 框架、云数据服务等,另外也包含对关系数据库的访问支持
- Lettuce:是一个可伸缩线程安全的 Redis 客户端,多个线程可以共享同一个 RedisConnection,它利用优秀的 Netty NIO 框架来高效地管理多个连接
- Spring Data Redis:是 Spring Data 项目中的一个主要模块,提供一个高度封装的“RedisTemplate”类实现了对 Redis 客户端 API 的高度封装,使得对 Redis 的操作更加便捷,而且Spring data redis 的连接池可以自动管理,针对数据的“序列化/反序列化”,提供了多种可选择策(如 RedisSerializer)
RedisTemplate
Spring Data Redis 为 Redis 提供了一个 RedisTemplate 工具类,它封装了 Redis 5 种数据结构的各种操作,比如:
opsForValue()
:操作字符串opsForHash()
:操作 hashopsForList()
:操作 listopsForSet()
:操作 setopsForZSet()
:操作有序 set
Spring Boot 整合 Redis
① 在pom.xml
中添加依赖:1
2
3
4
5
6
7
8
9
10<!-- Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- Lettuce 需要使用 commons-pool2 创建连接池 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
② 在application.yml
中进行相关配置:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22spring:
redis:
# Redis 服务器地址
host: localhost
# Redis 服务器连接端口
port: 6379
# Redis 数据库索引(默认为 0 )
database: 0
# Redis 服务器连接密码(默认为空)
password:
# 连接超时时间(毫秒)
timeout: PT10S
lettuce:
pool:
# 连接池最大连接数,默认 8,使用负值表示没有限制
max-active: 100
# 连接池最大阻塞等待时间,默认 -1,使用负值表示没有限制
max-wait: PT10S
# 连接池中的最大空闲连接,默认 8
max-idle: 30
# 连接池中的最小空闲连接,默认 0
min-idle: 1
③ 在平常的开发中我们可以中通过 Spring 的注入方式获取对RedisTemplate
对象的引用:1
2
private RedisTemplate<String, Object> redisTemplate;
④ 需要注意的是,首先需要自定义RedisTemplate
的序列化方式(需引入fastjson
包),具体过程如下:1
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/**
* 自定义 redis 序列化工具类
*
* @author lovike
* @since 2020-05-08
*/
public class CustomRedisSerializer implements RedisSerializer<Object> {
private final Charset charset;
public CustomRedisSerializer() {
this(StandardCharsets.UTF_8);
}
private CustomRedisSerializer(Charset charset) {
Assert.notNull(charset, "Charset must not be null!");
this.charset = charset;
}
public String deserialize(byte[] bytes) {
return (bytes == null ? null : new String(bytes, charset));
}
public byte[] serialize(Object object) {
if (object == null) {
return new byte[0];
}
if (object instanceof String) {
return object.toString().getBytes(charset);
} else {
String json = JSON.toJSONString(object);
return json.getBytes(charset);
}
}
}
⑤ 修改RedisTemplate
配置,之后才可在需要的地方注入RedisTemplate<String, Object>
:1
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
29import cn.lovike.seckill.common.redis.CustomRedisSerializer;
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.StringRedisSerializer;
/**
* RedisTemplate 配置
*
* @author lovike
* @since 2020-05-08
*/
public class RedisTemplateConfig {
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
CustomRedisSerializer customRedisSerializer = new CustomRedisSerializer();
redisTemplate.setKeySerializer(stringRedisSerializer);
redisTemplate.setValueSerializer(customRedisSerializer);
// redisTemplate.setHashKeySerializer(stringRedisSerializer);
redisTemplate.setHashKeySerializer(customRedisSerializer);
redisTemplate.setHashValueSerializer(customRedisSerializer);
return redisTemplate;
}
}
RedisTemplate 源码解读
为什么我们都没有在 Spring 中注入RedisTemplate
对象,就能直接声明获取到它的引用呢?
来看一下 Spring Boot 中的源码:1
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
30package org.springframework.boot.autoconfigure.data.redis;
import ...
({RedisOperations.class})
({RedisProperties.class})
({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})
public class RedisAutoConfiguration {
public RedisAutoConfiguration() {
}
(
name = {"redisTemplate"}
)
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}
通过源码知道,在 Spring Boot 启动后会自动注入两个 Bean:
RedisTemplate
StringRedisTemplate
那么它们有何不同呢?
下面分别看一下RedisTemplate
和StringRedisTemplate
的源码(部分):1
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
48import ...
public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperations<K, V>, BeanClassLoaderAware {
...
public RedisTemplate() {
}
public void afterPropertiesSet() {
super.afterPropertiesSet();
boolean defaultUsed = false;
if (this.defaultSerializer == null) {
this.defaultSerializer = new JdkSerializationRedisSerializer(this.classLoader != null ? this.classLoader : this.getClass().getClassLoader());
}
if (this.enableDefaultSerializer) {
if (this.keySerializer == null) {
this.keySerializer = this.defaultSerializer;
defaultUsed = true;
}
if (this.valueSerializer == null) {
this.valueSerializer = this.defaultSerializer;
defaultUsed = true;
}
if (this.hashKeySerializer == null) {
this.hashKeySerializer = this.defaultSerializer;
defaultUsed = true;
}
if (this.hashValueSerializer == null) {
this.hashValueSerializer = this.defaultSerializer;
defaultUsed = true;
}
}
if (this.enableDefaultSerializer && defaultUsed) {
Assert.notNull(this.defaultSerializer, "default serializer null and not all serializers initialized");
}
if (this.scriptExecutor == null) {
this.scriptExecutor = new DefaultScriptExecutor(this);
}
this.initialized = true;
}
...
}
1 | import ... |
对它们而言:1
2
3
4
5
6
7
8
9// 若没有特殊的设置,key 和 value 都是使用 defaultSerializer = new JdkSerializationRedisSerializer(); 进行序列化的
// 下面是对 key 的默认序列化器,默认是 JdkSerializationRedisSerializer。
redisTemplate.setKeySerializer();
// 下面是对 value 的默认序列化器,默认是 JdkSerializationRedisSerializer。
redisTemplate.setValueSerializer();
//对 hash 结构数据的 hashkey 序列化器,默认是 JdkSerializationRedisSerializer。
redisTemplate.setHashKeySerializer();
//对 hash 结构数据的 hashvalue 序列化器,默认是 JdkSerializationRedisSerializer
redisTemplate.setHashValueSerializer();
从上述源码可以看出它们的区别:
StringRedisTemplate
继承自RedisTemplate
RedisTemplate
是一个泛型类,而StringRedisTemplate
不是StringRedisTemplate
只能对key=String,value=String
的键值对进行操作,RedisTemplate
可以对任何类型的key-value
键值对操作- 它们各自序列化的方式不同,但最终都是得到了一个字节数组,比如
StringRedisTemplate
使用的是StringRedisSerializer
类;RedisTemplate
使用的是JdkSerializationRedisSerializer
类。反序列化,前者则是得到String
,后者得到Object
- 另外针对数据的“序列化/反序列化”,提供了多种可选择策略(
RedisSerializer
):JdkSerializationRedisSerializer
:该序列化方法为 Jdk 提供。首先要求被序列化的类实现 Serializeable 接口,然后通过 Jdk 对象序列化的方法保存。(注:该序列化保存的对象,即使是个 String 类型的,在 Redis 控制台,也是看不出来的,因为它保存了一些对象的类型的额外信息。是目前最常用的序列化策略。StringRedisSerializer
:通过 String.getBytes() 来实现的。由于在 Redis 中,所有存储的值都是字符串类型的。所以该方法保存后通过 Redis-cli 控制台,可以清楚的查看到具体保存了什么 key 和 value,是最轻量级和高效的策略JacksonJsonRedisSerializer
:jackson-json
工具提供了 JavaBean Json 之间的转换能力,可以将 POJO 实例序列化成 Json 格式存储在 Redis 中,也可以将 Json 格式的数据转换成 POJO 实例。因为jackson工具在序列化和反序列化时,需要明确指定 Class类型,因此策略封装起来稍微复杂
首先小小的总结一下:
RedisTemplate
在操作数据的时候,存入数据前会先将数据序列化成字节数组,然后再存入 Redis 数据库(默认使用JdkSerializationRedisSerializer
序列化),在 Redis 控制台查看的数据是以不可读的形式展现的,即字节数组方式显示StringRedisSerializer
在操作数据的时候就是通过String.getBytes()
来实现的。由于在 Redis 中,所有存储的值都是字符串类型的。因此该方法保存后,通过 Redis-cli 控制台(或 Redis 图形化工具),可以清楚的查看到具体保存了什么 key 和 value
参考
文章信息
时间 | 说明 |
---|---|
2019-04-10 | 初稿 |
2022-12-21 | 部分重构 |