一、Redis简介
- Redis是一个开源的,使用 C 编写,高性能的Key-Value的NoSQL数据库。
- SQL :关系型数据库,例如:MySQL,Oracle等等
- NoSQL :Not Only SQL 不仅仅是SQL,表示是非关系型数据库
Redis特点
- 基于
内存
- 可持久化数据
- 具有丰富的数据结构类型,适应非关系型数据的存储需求
- 支持绝大多数主流开发语言,如C、C++、Java、Python、R、JavaScript等。
- 支持集群模式,高效、稳定。
Redis的数据模型
- 键值对形式。(key:value模型)
- Redis的数据结构类型,指的就是Redis值的结构类型(即value的数据类型)。
Redis作用
- 本质是数据库,能存储数据。
- Redis能灵活处理非关系型数据的读、写问题,是对MySQL等关系型数据库的补充。
- 新浪微博就是使用Redis集群做数据库。
- 应用场景:微博、即时通讯、验证码,单点登录,缓存等
- . 缓存数据。
-
所谓缓存,就是
将数据加载到内存中后直接使用
,而不是每次都通过IO流从磁盘上读取。而Redis则是将数据直接存储在内存中,只有当内存空间不足时,将部分数据持久化到磁盘上。- 好处:读写效率高。
-
二、Redis安装
- 因为Redis官方只提供了源码,并没有提供经过编译之后的安装包,直接在Linux安装相对繁琐复杂。
- 所以使用docker安装(前提需要熟悉docker)
第1步、下载redis的docker镜像
docker pull redis:6.2.13
第2步、 创建并启动容器
- 创建本地映射目录
mkdir -p /usr/local/docker/redis/config
mkdir -p /usr/local/docker/redis/data
- 并把redis.conf配置文件上传到 /usr/local/docker/redis/config目录(使用客户端软件Xsheel,xftp,MobaXterm等把redis.conf配置文件上传到该目录下)
第3步、 使用docker命令启动名称创建容器
docker run --restart=always \
-p 6379:6379 \
--name redis \
-v /usr/local/docker/redis/config/:/etc/redis/ \
-v /usr/local/docker/redis/data:/data \
-d redis:6.2.13 redis-server /etc/redis/redis.conf
命令解释
docker run 创建并运行
--restart=always 运行容器随Linux开机启动
-p 6379:6379 端口映射 -》 -p 宿主机对外暴露端口:容器端口
--name redis 指定容器名称
-v /usr/local/docker/redis/config/:/etc/redis/ 把redis容器的/etc/redis/目录 到宿主机的 /usr/local/docker/redis/config/(映射配置文件)
-v /usr/local/docker/redis/data:/data 映射redis持久化数据目录
-d redis:6.2.13 redis-server /etc/redis/redis.conf
-d 进程在后台启动的模式
redis:6.2.13 是redis镜像版本
redis-server /etc/redis/redis.conf redis容器中的服务指定读取的配置文件位置
第4步、查看容器
使用docker ps 指令查看运行的容器
如果看到redis,说明redis安装成功
到这里就说明安装成功了
第5步、进入容器
docker exec -it redis bash
第6步、登录redis
-
因为默认没有设置密码,所以进去无需登录,直接就可以使用
-
启动redis客户端,登录 /usr/local/bin/redis-cli
redis.conf常用配置说明
修改了配置文件之后,需要重新启动redis服务
docker restart redis
1、requirepass foobar(需要自己操作的)
(vim进入命令模式,输入/然后加上想要查找的关键词,回车进行搜索,按n进行查找下一个)
给redis设置密码(配置文件里面默认是没有配置的)
- 修改配置文件后,需要重新启动redis
2、databases 16 (不需要自己操作的)
Redis默认有16个数据库,寻址下标从0开始。
默认连接db0
3、 port 6379(不需要自己操作的)
指定redis的服务端口,默认6379.
4、配置redis的bind(需要自己操作的)
只有操作了此步骤外界才能访问当前redis
- Redis默认只能当前主机访问127.0.0.1需要修改配置其他机器才能访问
5、dbfilename dump.rdb、dir ./(不需要自己操作的)
- 指定数据持久化的文件名及目录。
- docker创建默认的数据持久化目录在/data 目录
使用客户端访问
- 在windows上安装访问客户端(傻瓜式安装)
https://github.com/qishibo/AnotherRedisDesktopManager/releases
- 连接:填入对应的redis所在的ip地址,还有端口号,以及密码,即可连接成功。
三、Redis的使用
Redis的键key与值value(数据结构类型)
- Redis存储的是key-value结构的数据,其中key是字符串类型,value有5种常用的数据类型。
- Redis的数据结构类型,指的就是redis的值value的类型;
- Redis常用的数据结构类型:string、list、set、sortedSet、hash
- 字符串 string:普通字符串,Redis中最简单的数据类型(常用)
- 哈希 hash:也叫散列,类似于Java中的HashMap结构(一般拿来存储对象)
- 列表 list:
按照插入顺序排序
,可以有重复
元素,类似于Java中的LinkedList - 集合 set:
无序
集合,没有重复元素,类似于Java中的HashSet - 有序集合 (sorted set / zset):集合中每个元素关联一个分数(score),根据分数升序排序,没有重复元素
1、Redis的键key
-
key的类型:redis的key 值是
二进制储存
的,这意味着可以用任何二进制序列作为key值,从形如”foo”的简单字符串到一个JPEG文件的内容都可以。- 空字符串也是有效key值。
- redis建议使用
字符串
做为key的类型
-
key取值规范:
-
- 键值不需要太长,消耗内存,在数据中查找这类键值的计算成本较高
-
- 键值不宜过短,可读性较差,通常建议
见名知意
。
- 键值不宜过短,可读性较差,通常建议
-
-
key的取值举例:
set user:id:1:username lisi
# set user:id:1:username lisi命令可以理解为将一个用户的用户名设置为lisi,
# 其中set是Redis提供的设置命令,user:id:1:username是键(key),
# lisi是该键对应的值(value)。这个命令实际上是将用户ID为1的用户的用户名设置为lisi。
# 在Redis中,键值对的设计非常灵活,可以根据实际情况进行设置。
set user:id:1:password 111111
set user:id:1:email lisi@163.com
key命令
-
exists key :检查给定key是否存在。(1表示存在,0表示不存在)
- 注意事项,不支持通配符
- 注意事项,不支持通配符
-
del key :删除一个key
-
del key1 key2 key3:删除多个key
-
keys pattern (模糊查找):查找所有符合给定模式 pattern 的 key 。
- keys * :匹配数据库中所有 key 。
- keys n?me: 匹配 name、neme、nfme 等。
- keys n* :匹配 name、neme、naaaaame等。
- keys n[ae]me :只能匹配 name、neme。
-
expire key seconds:指定key的过期时间。
- 新添加的key,如果没有指定过期时间,则会一直保存。
- 可以对一个已经带有生存时间的key执行EXPIRE命令,新指定的生存时间会取代旧的生存时间。
-
ttl key:查看某个key的剩余过期时间,返回值:
- -2 表示这个key已经过期,删除掉
- -1 表示没有设置过期时间
- 其它表示剩余的生存时间,单位为秒。
-
rename
- 语法格式:rename key newkey,表示将 key 改名为 newkey 。
- 当 key 不存在时,返回一个错误。
- 当 newkey 已经存在时, RENAME 命令将覆盖旧值。
-
type key :查看key对应的value的数据结构类型。
-
get key :查看某一个key的值
其它key命令见redis帮助文档 http://doc.redisfans.com/
2、Redis的值Value
String类型
- string类型是redis最常用的数据结构类型,存储的值为字符串
String相关命令
-
set key value :设置一个key,值为value,类型为String类型;
- 如果这个key已经存在,则更新这个key的值。返回oK成功
- 如果这个key已经存在,则更新这个key的值。返回oK成功
-
setnx key value : 如果这个key不存在,则设置一个key,值为value;
- 如果key存在,则不做更新。
- 返回值
- 1 表示成功
- 0 表示失败
-
get key: 获取key对应的value值;
- 如果key不存在,则返回nil
- 如果key不存在,则返回nil
-
mget key1 key2 key3 :一次获取多个key的值,如果对应key不存在,则对应返回nil
-
incr key : 将key 中储存的数字值增一,然后返回。
- 如果这个key不存在,那么key的值会先被初始化为0,然后再执行INCR操作。
- 如果这个key对应的value值,不能表示数字,则会返回一个错误。
-
incrby key increment :将key增加指定的步长值。
- increment是步长
- increment是步长
-
decr key (decrement):将key 中储存的数字值减一,然后返回。
- 如果这个key不存在,那么key的值会先被初始化为0,然后再执行DECR操作。
- 如果这个key对应的value值,不能表示数字,则会返回一个错误。
-
decrby key decrement :将key减少对应的步长值。
-
append key value :如果key已经存在,则将value追加到这个key原先的value值的末尾。如果这个key不存在,则执行set操作。
String类型的应用场景
- 做与统计有关的业务,如新浪微博(微信朋友圈)中的点赞功能
- 购物车的商品添加数量的功能(+,-键的功能)
解决多线程的线程安全问题
- Redis6.0以前的key是单线程模式,这就意味一瞬间只有一个线程能够持有这个key,所以可以使用redis解决部分涉及线程安全的业务。
- 比如,在初级时候通过多线程模拟卖票,使用加锁的方式,保证只有一个线程能够持有锁,进行买票业务。还有点赞功能基本上都是使用redis技术实现的。redis6.0版本前是单线程的,6.0之后是支持多线程的,默认多线程是关闭的
List类型
-
value类型是List的特点:
- 基于Linked List实现
- 元素是字符串类型
- 列表头尾增删快,中间增删慢,增删元素是常态
- 元素可以重复出现
- 最多包含(2^32)-1元素
-
列表的索引
- n 从左至右,从0开始
- n 从右至左,从-1开始
list相关命令
-
lpush key value [value …] :将一个或多个值value插入到列表key的表头(即从左边插入);
- 如果有多个value值,那么各个value值按从左到右的顺序依次插入到表头:比如说,对空列表mylist执行命令LPUSH mylist a b c,列表的值将是 c b a 这等同于原子性地执行 LPUSH mylist a 、 LPUSH mylist b 和 LPUSH mylist c 三个命令;
- 如果key 不存在,一个空列表会被
创建
并执行 LPUSH 操作。 - 当key 存在但不是列表类型时,返回一个错误。
-
rpush key value [value …] :尾部添加(从右向左),操作同上。
-
llen key :返回key对应list的长度;
- key不存在返回0
- 如果key对应类型不是list返回错误
-
lindex key index :index元素在list列表中的下角标,从0开始;
- lindex 是从左到右取元素
- lindex 是从左到右取元素
-
lrange key start stop :获取指定区间的所有元素;
- 下角标从0开始,0表示第一个元素,1表示第二个,依次类推;
- -1表示最后一个元素,-2表示倒数第二个元素,依次类推;
-
lpop key :移除并返回列表中的第一个元素
-
rpop key :移除并返回列表中的最后一个元素。
List类型应用场景
- 处理排名类业务。如新浪微博评论、论坛回帖楼层等。
- 聊天室
Hash(散列)类型
- hash数据类型 是一个string类型的 field 和 value 的映射表,hash特别适合用于存储对象
- hash类型的特点:
-
- 由Field和与之关联的value组成map键值对
-
- field和value是字符串类型;
-
- 一个hash中最多包含2^32-1键值对。
-
hash相关命令
-
hset key field value :设置hash field为指定值;
- 如果key不存在,则先创建;
- 如果field已经存在,那么将更新这个field的值。
-
hget key field :获取指定的hash field
-
hmget key filed1…fieldN :获取全部指定的hash的key对应的 filed
-
hmset key filed1 value1 … filedN valueN :同时设置hash的多个field
-
hkeys key :返回hash对应的key的的所有field
-
hvals key 返回hash对应的key的所有value
-
hexists key field :判断指定的key对应的field是否存在
-
hdel key field :删除指定的hash指定的key对应的 field
-
hlen key :返回指定hash的field数量
- hgetall key 返回hash的所有filed和value
Hash的用途(能使用hash的时候尽量使用hash)
- 节约内存空间:
- redis每创建一个键(key),都会为这个键储存一些附加的管理信息(比如这个键的类型,这个键最后一次被访问的时间等等)
- redis的key相对于值来说,更珍贵!!!
- 所以数据库里面的键越多,redis数据库服务器在储存附加管理信息方面耗费的内存就越多,在获取key对应的value值时cpu的开销也会更多
- Hash结构可以将具有关联关系的一组key-value,存储到同一个hash结构中,从而减少key的数量。
hash不适用的场景
- 如果我们仅仅只对一个字段设置过期,就不建议使用hash。
- Redis的key的过期功能只能对键操作,而Hash结构不能单独对某一个filed设置过期功能。
说明:在实际开发中,能使用hash的时候,尽量使用hash!!
Set类型(集合)
- redis的value的数据类型为set的特点:
-
- 无序的、去重的;
-
- 元素是字符串类型;
-
- 最多包含(2^32)-1元素
-
set相关命令
-
sadd key member [member …](member要无序不重复) :
- 将一个或多个member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略。
- 假如key 不存在,则创建一个只包含 member 元素作成员的集合。
- 当key 不是集合类型时,则返回一个错误。
-
smembers key :
- 返回集合key 中的所有成员。
- 不存在的key 被视为空集合。
- 不是set类型的key会报错
-
spop key :移除并返回集合中的一个随机元素。
- 被移除元素是随机的。
- 当key不存在或key是空集时,返回nil。
-
scard key :
- 返回集合key的基数(集合中元素的数量)。
- 当key不存在时,返回0。
-
sinter key [key …] :
- key只有一个时返回一个集合的全部成员
- key有多个时,返回的是所有key集合的交集。
- 不存在的key 被视为空集。
-
sunion key [key …] :
- 如果只有一个key时,返回一个集合的全部成员
- 如果有多个key时,饭返回所有key集合的并集。
- 不存在的key 被视为空集。
-
sdiff key [key …] :
- key只有一个时,返回一个key集合的全部成员
- key有多个时,返回所有key集合之间的差集。
- 不存在的key 被视为空集。
set数据类型应用场景
- 新浪微博的共同关注
-
需求:当用户访问另一个用户的时候,会显示出两个用户共同关注哪些相同的用户
-
设计:将每个用户关注的用户放在集合中,求交集即可
-
实现如下:
peter={'john','jack','may'}
ben={'john','jack','tom'}
那么peter和ben的共同关注为:
SINTER peter ben 结果为{'john','jack'}
SortedSet类型
- Redis的value的数据类型SortedSet数据类型的特点:
-
- 类似Set集合;
-
- 有序的、去重的;
-
- 元素是字符串类型;
-
- 每一个元素都关联着一个浮点数分值(Score),并按照分值从小到大的顺序排列集合中的元素。分值可以相同
-
- 最多包含2^32-1元素
-
-
zadd key [sort member sort member] : 向有序集合添加一个或多个成员
- 如:zadd set1 1 zhangsan 2 lisi
-
zrange key start end [withscores] :查询指定范围的值升序排序
- 如:zrange set1 0 10
- Start 索引 从0开始 stop 结束索引或者-1(最后一个)
-
zrevrange ket start end [withscores]: 查询指定范围的值降序排序
- 如:zrange set1 0 10
- Start 索引 从0开始 stop 结束索引或者-1(最后一个)
-
zcount key start end :统计一个范围内元素的个数
- 如:zcount set1 0 10
- 返回有序集 key 中, score 值在 min 和 max 之间(默认包括 score 值等于 min 或 max )的成员的数量
-
zcard key: 统计元素的个数
- 如:zcard set1
- 如:zcard set1
-
zrank key 返回成员的索引号
- 如:zrank set1 lucy
- 如:zrank set1 lucy
-
zrem key member1 […membern] 删除成员
- 如:zrem set1 zhangsan
- 如:zrem set1 zhangsan
sortedSet数据类型的适用场景
适用于需要有序且唯一的业务或操作:
- 网易音乐排行榜
- 分析:
- 每首歌的歌名作为元素(唯一、不重复)
- 每首歌的播放次数作为分值
- ZREVRANGE来获取播放次数最多的歌曲(就是最多播放榜了,云音乐热歌榜,没有竞价,没有权重)
- 分析:
四、在java中操作redis
第一步:创建springboot项目:
- 选择redis依赖
第二步:进行redis相关配置
# redis??
spring:
data:
redis:
host: 192.168.70.130 #虚拟机地址
port: 6379 # 端口号
password: 123456 # 密码
connect-timeout: 60000 #
lettuce:
pool: #?????
max-active: 512 #?????
max-idle: 128 #???????
min-idle: 128 #???????
max-wait: 1000ms #????????
第三步:写测试类(StringRedisTemplate测试类):
- StringRedisTemplate测试类:
- StringRedisTemplate操作的都是字符串类型的数据
package com.knife;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.*;
import java.time.Duration;
import java.util.*;
@SpringBootTest
class RedisDemoApplicationTests {
@Resource
private StringRedisTemplate stringRedisTemplate;
/**
* String类型操作
*/
@Test
void testString() {
//获取操作String类型的对象
ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();
//设值
opsForValue.set("name", "zhangsan");
opsForValue.set("age", "18");
//获取值
String name = opsForValue.get("name");
System.out.println("name = " + name);
//递增
opsForValue.increment("star");
//递减
opsForValue.increment("star");
//设值key超时自动清除1s超时(一般用并发简单的分布式锁)
opsForValue.set("temp", "suiyi", Duration.ofSeconds(1));
//删除
// stringRedisTemplate.delete("age");
// stringRedisTemplate.delete("name");
}
/**
* List类型操作
*/
@Test
void testList() {
ListOperations<String, String> opsForList = stringRedisTemplate.opsForList();
//添加单个值(左)
opsForList.leftPush("names", "张三");
//添加单个值(右)
opsForList.rightPush("names", "李四");
//添加多个值(右)
//添加多个值(左)
opsForList.leftPushAll("names", "小明", "小红", "小芳");
//添加多个值(右)
opsForList.rightPushAll("names", "tom", "jerry", "ben");
//获取值(获取所有)
List<String> names = opsForList.range("names", 0, -1);
System.out.println("names = " + names);
//删除(从左)
String name = opsForList.leftPop("names");
System.out.println("name = " + name);
//删除(从右)
name = opsForList.rightPop("names");
}
/**
* Hash类型操作
*/
@Test
void testHash() {
//获取hash对象
HashOperations<String, Object, Object> opsForHash = stringRedisTemplate.opsForHash();
//设置hash以及字段值
opsForHash.put("user:id:1", "name", "张三");
opsForHash.put("user:id:1", "age", "18");
opsForHash.put("user:id:1", "sid", "202108764226");
opsForHash.put("user:id:1", "gender", "男");
opsForHash.put("user:id:1", "phone", "19876850907");
//添加map
HashMap<String, Object> userMap = new HashMap<>();
userMap.put("name", "小敬哥");
userMap.put("age", "29");
userMap.put("gender", "男");
userMap.put("sid", "202108764226");
opsForHash.putAll("user:id:2", userMap);
// 查询key的所有数据
Map<Object, Object> entries = opsForHash.entries("user:id:1");
System.out.println(entries);
//删除指定的1-n个field(字段)
opsForHash.delete("user:id:2", "age", "gender");
//获取单个field值
String name = (String) opsForHash.get("user:id:1", "name");
// 获取所有字段
List<Object> values = opsForHash.values("user:id:1");
System.out.println(values);
//获取多个field值
List<Object> fields = Arrays.asList("name", "age", "gender");
List<Object> objects = opsForHash.multiGet("user:id:1", fields);
System.out.println("objects = " + objects);
}
/**
* Set类型操作
*/
@Test
void testSet() {
//获取操作Set对象
SetOperations<String, String> opsForSet = stringRedisTemplate.opsForSet();
//添加元素
opsForSet.add("language1","java","php","c");
opsForSet.add("language2","java","go","c++");
opsForSet.add("girls", "西施", "貂蝉", "王昭君", "杨玉环", "凤姐");
// 随机删除一个字段并返回字段
String language1 = opsForSet.pop("language1");
System.out.println(language1);
//获取所有元素
Set<String> girls = opsForSet.members("girls");
System.out.println("girls = " + girls);
//删除指定的元素
opsForSet.remove("girls", "凤姐", "杨玉环");
// 取两个集合的交集
Set<String> intersect = opsForSet.intersect("language1", "language2");
System.out.println("intersect="+ intersect);
// 取两个集合的全集
Set<String> union = opsForSet.union("language1", "girls");
System.out.println("union =" + union);
}
/**
* SortedSet操作
*/
@Test
void testSortedSet() {
//获取SortedSet对象
ZSetOperations<String, String> opsForZSet = stringRedisTemplate.opsForZSet();
//添加元素
opsForZSet.add("fruits", "西瓜", 1.0);
opsForZSet.add("fruits", "苹果", 2.0);
opsForZSet.add("fruits", "梨", 3.0);
opsForZSet.add("fruits", "火龙果", 4.0);
opsForZSet.add("fruits", "葡萄", 3.5);
//获取所有元素(按分值低到高)
// 从0开始取,取到末尾,-1表示末尾的元素
Set<String> fruits = opsForZSet.range("fruits", 0, -1);
System.out.println("fruits = " + fruits);
//获取所有元素(按分值高到低)
fruits = opsForZSet.reverseRange("fruits", 0, -1);
System.out.println("fruits = " + fruits);
//获取分值范围的元素
Long count = opsForZSet.count("fruits", 1.0, 2.0);
System.out.println("count = " + count);
// 按照分值范围获取数据
Set<String> fruits1 = opsForZSet.rangeByScore("fruits", 3.0, 5.0);
System.out.println(fruits1);
//删除
opsForZSet.remove("fruits","西瓜","火龙果");
System.out.println(opsForZSet.reverseRange("fruits", 0, -1));
}
}
第三步:写测试类(RedisTemplate测试类):
- RedisTemplate测试类:
- RedisTemplate可以存储对象
在上面创建项目的基础上添加下面的依赖:
<!-- lombok的依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- 针对RedisConfig的依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
- pojo类需要
实现序列化接口
,因为redis存储对象时候实际上是将对象进行序列化数据后存储到Redis
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
private Integer id;
private String name;
private Integer age;
private String phone;
}
测试类:
package com.knife;
import com.knife.pojo.User;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
@SpringBootTest
public class RedisTemplateTest {
@Resource
private RedisTemplate<String,Object> redisTemplate;
@Test
void test1(){
ValueOperations<String, Object> vos = redisTemplate.opsForValue();
User user = new User(1,"zhangsan",11,"12349023910");
// 要把对象存入redis,需要把该类实现Serializable,这样才可以序列号
vos.set("user",user);
Object o = vos.get("user");
System.out.println(o);
}
}
- RedisTemplate可以直接将我们的程序的Java对象存储到Redis中,不过·默认会将非字母和数字的其他数据转换成hex16进制·,虽然不影响程序运行,但是不太方便开发者进行开发阅读。
配置RedisTemplate序列化器
- 一般都是将Java对象序列化为json,也可以直接将Redis中数据获取出来直接反序列化成Java对象
- 这里需要配置RedisTempate将数据存储到Redis的时候序列化为JSON字符串选用的序列化器
- json序列化我们可以使用SpringMVC官方推荐的jackson或者是alibba的fastjson
- 这里需要配置RedisTempate将数据存储到Redis的时候序列化为JSON字符串选用的序列化器
创建RedisConfig配置类
package com.knife.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
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;
@Configuration
public class RedisConfig {
/**
* RedisTemplate配置
*/
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
// 配置redisTemplate
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 设置序列化
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
// 这里爆红是因为过时了,但是还能用
jackson2JsonRedisSerializer.setObjectMapper(om);
// key序列化(使用redis自身的序列化)
redisTemplate.setKeySerializer(new StringRedisSerializer());
// value序列化(使用springboot自带的json序列化)
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
// Hash key序列化(使用redis自身的序列化)
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
// Hash value序列化(使用springboot自带的json序列化)
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
继续使用上面的测试类进行测试;
- RedisTemplate使用序列化器以后存储的效果就是一个json字符串,实际开发也推荐使用此种方式。