Centos7上安装Reids&Redis的基本使用&Java操作Redis
安装Redis
首先打开虚拟机的终端。
输入命令 ip addr ,查看此时的IP地址。
在输入下面命令
yum install -y gcc tcl
出现下述页面即代表成功。
下面将会使用 Xftp 软件将 redis的安装包上传到虚拟机。
打开Xfpt软件。点击新建,并且输入名称和主机,然后点击确定。
下面选择上图中设置的名称,然后点击连接。
点击接受并保存。
然后输入你此时虚拟机上登录的用户名和密码即代表连接成功。
然后在Xfpt软件的右上端找到虚拟机上要安装redis的位置,这里安装路径为 /url/local/src,然后将redis的安装包拖拽到右侧即可。
注意 : 这里选择 /url/local/src,因为这里面主要存放一些第三方的源代码。
然后在虚拟机的终端上输入以下命令。
cd /usr/local/src/
进入到 /usr/local/src/ 目录后,然后输入以下命令开始解压redis的安装包。
tar -zxvf redis-6.2.6.tar.gz
此时输入 ls 命令可以看到redis已经解压成功了。
然后进入redis的安装目录
cd redis-6.2.6
然后输入开始编译命令
make && make install
等待安装,成功后就会出现如下显示。
注意:
Redis的默认安装路径是在 /usr/local/bin 的目录下。该目录已经默认配置到环境变量,因此可以在任意目录下运行这些命令。
redis-cli:是redis提供的命令行客户端。
redis-server:是redis的服务端启动脚本。
redis-sentinel:是redis的哨兵启动脚本。
启动Redis
默认启动Redis
在任意目录下输入以下命令即可启动Redis。
redis-server
下面图片即代表启动成功。
注意:这种方式启动属于前台启动,会阻塞整个会话窗口,如果窗口关闭或者按下 Ctrl + C,则代表着Redis停止。如果想要使用这种方式,则必须在打开一个终端使用。
指定配置文件启动
如果要让Redis以后台方式启动,则必须修改Redis配置文件,就在我们之前解压的Redis安装包下 (/usr/local/src/redis-6.2.6
),名字叫redis.conf
我们需要使用下述命令将 redis.conf 文件备份一份。以防止文件内容无法恢复。
cp redis.conf redis.conf.bck
通过下述命令修改 redis.conf 文件的配置。
vim redis.conf
redis.conf文件修改的一些配置,注意:修改完成后一定要保存。这里必须要修改 bind 0.0.0.0 与 daemonize yes,其他的看自己选择。
# 允许访问的地址,默认是127.0.0.1,即就是只能在本地访问。
# 如果修改为 0.0.0.0 ,则可以在任意IP访问,生产环境不要设置为0.0.0.0。
bind 0.0.0.0
# 守护线程,修改为yes后即可在后台允许。
daemonize yes
# 设置密码,设置后访问Redis必须输入密码。
requirepass 123456
# 监听的端口。
port 6379
# 工作目录,默认是当前目录,也就是允许redis-server时的命令、日志、持久化等文件会保存在这个目录。
dir .
# 数据库数量,设置1,代表只使用1个库,默认有16个库,编号0~15
databases 1
# 设置redis能够使用的最大内存
maxmemory 512mb
# 日志文件,默认为空,不记录日志,可以指定日志文件名
logfile "redis.log"
# 设置保护模式 -- 需要密码登录
protected-mode yes
使用指定配置文件启动Reids
# 进入到Redis的安装目录
cd /usr/local/src/redis-6.2.6
# 启动Redis
redis-server redis.conf
此时发现并没有显示什么,那么使用下述命令判断是否在后台启动了Redis。
ps -ef | grep redis
如果出现了下面的图片所出现的,即意味着后台启动成功。
设置Redis开机自启
①:创建一个系统服务文件。
vi /etc/systemd/system/redis.service
②:给其文件添加内容。
[Unit]
Description=redis-server
After=network.target
[Service]
Type=forking
ExecStart=/usr/local/bin/redis-server /usr/local/src/redis-6.2.6/redis.conf # 注意redis的安装路径
PrivateTmp=true
[Install]
WantedBy=multi-user.target
③:重载系统服务
systemctl daemon-reload
④:启动Redis
systemctl start redis
⑤:停止、重启Redis的命令
# 重启
systemctl restart redis
# 停止
systemctl stop redis
⑥:查看Redis的状态
# 查看状态
systemctl status redis
Redis客户端
Redis命令行客户端
Redis安装成功后会自带一个命令行客户端 :redis-cli。
使用方式:
redis-cli [options] [commonds]
常见的options有:
-h 127.0.0.1 : 指定要连接的redis节点的IP地址,默认是127.0.0.1。
-p 6379 :指定要连接的redis节点的端口,默认是6379。
-a 123456:指定redis的访问密码。
常见的commands就是Redis的操作命令,如:
ping:与redis服务端做心跳测试,服务端正常会返回 PONG。
注意:这里如果不指定commonds的话,就会进入 redis-cli
的交互控制台。也就是说我们想要操作Redis,必须要指定commands。
如下图所示:
这里有两种方式进入redis-cli 来操作redis。
这里不管用哪种方式,必须要进入到Redis的默认安装路径 /usr/local/bin
的目录下进行操作。
①:需要直接指定commands
redis-cli -h 127.0.0.1 -p 6379 -a 123456
出现警告: Warning: Using a password with ‘-a’ or ‘-u’ option on the command line interface may not be safe. 意思是使用这种方式不安全。使用下面方式就不会出现这种情况。
②:进入redis-cli
的交互控制台后输入commands。
redis-cli
然后输入。
AUTH 123456 # 123456是自己在redis.conf文件中设置的密码
完成后会显示一个OK。
图形化桌面客户端
这里使用RDM作为图形化界面的客户端。
打开RDM软件,先点击连接到 Redis 服务器,然后输入名字和虚拟机的IP地址之后,点击确定。
连接Redis可能会出现的问题
连接RDM失败的原因有两种
①:没有输入密码
如果你在redis.conf配置文件中设置了密码,那么这里需要输入你设置的密码。如果没有设置,那么就是属于下面的情况。
②:没有关闭防火墙
首先输入下述命令,查看防火墙的状态。
systemctl status firewalld
如果它这里显示 active(running)
,意思是防火墙开启,我们需要使用下述命令对它进行关闭。
# 关闭防火墙的命令
systemctl stop firewalld
Redis的常用命令
Redis的数据结构介绍
Redis是一个key-value的数据库,key一般是String,value的类型有多种。
基本类型
数据类型 | 存储数据示例 |
---|---|
String | Hello World |
Hash | {name:“Tom”,age:18} |
List | [A,B,C,C] |
Set | {A,B,C} |
SortedSet | {A:1,B:2,C:3} |
特殊类型
数据类型 | 存储类型示例 |
---|---|
GEO | {A:(10.5,.22.5)} |
BitMap | 0110110101110101011 |
HyperLog | 0110110101110101011 |
操作通用命令
查看Redis的操作命令的类型
我们可以通过两种方式来查看操作Redis命令。
①:我们可以在Redis官网查看这些命令。
②:我们可以在redis-cli
的交互控制台查看命令。具体操作看下述命令。
# 进入redis-cli的交互控制台
redis-cli
# 输入密码,这里账号可以省略
AUTH 123456 # 这里输入自己在redis-conf配置文件中设置的密码
# 查看Redis的操作命令的类型
help
# 查看Redis的通用操作命令
help @generic
# 查看某一个命令的具体用法,这里查看keys命令的用法
# help [command]
help keys
使用常用的通用命令
KEYS
:查看符合模板的所有key,不建议在生产环境设备上使用,因为如果存在很多个key,那么会影响到查询效率,并且在查询key的时候,Redis进程会阻塞。
KEYS pattern
# 查询所有的key
KEYS *
# 模糊查询key 例:查询name
KEYS n*
DEL
:删除一个指定的KEY。
DEL key
# 例:删除name
DEL name
EXISTS
:判断key是否存在。
EXISTS key
# 例:判断 name 是否存在,如果存在会返回1,不存在返回0.
EXISTS name
EXPIRE
:给一个key设置有效期,有效期到期时该key会自动删除。
EXPIRE key seconds
# 例:给name设置10s的有效期
EXPIRE name 10
TTL
:查看一个KEY的剩余有效期。
TTL key
# 例:查看 name 的剩余有效期
TTL name
操作String的常用命令
String类型也就是字符串类型,是Redis中最简单的存储类型。其中value是字符串,而根据字符串的格式不同,又可以分为3类。
- string: 普通字符串。
- int:整数类型,可以做自增、自减操作。
- float:浮点类型:可以做自增、自减操作。
注意:不管是哪种格式,底层都是字节数组形式存储,只不过是编码方式不同。字符串类型的最大空间不能超过512m。
SET
:添加或修改已经存在的一个String类型的键值对。
SET key value
# 例:添加一个键值对 age:10
SET age 10
# 例:修改一个键值对 name:lisi
SET name lisi
GET
:根据key获取String类型的value。
GET key
# 例:获取name的值
GET name
MSET
:批量添加多个String类型的键值对。
MGET key value [key value ...]
# 例:添加两个键值对, email:"123@qq.com" height:178
MSET email 123@qq.com height 178
MGET
:根据多个key获取多个String类型的value。
MGET key [key ...]
# 例:获取 email、name 的值
MGET email name
INCR
:让一个整型的key自增1。
INCR key
# 例: 将age的年龄增加一岁
INCR age
INCRBY
:让一个整型的key按照指定的步长增长。
INCRBY key increment
# 例:将age的年龄增加两岁
INCRBY age 2
INCRBYFLOAT
:让一个浮点类型的key按照指定的步长增长。
INCRBYFLOAT key increment
# 例:将 num 的数增加2.5
INCRBYFLOAT num 2.5
SETNX
:添加一个String类型的键值对,前提是这个key不存在,否则不执行。
SETNX key value
# 例:添加 name:wang 键值对,但是因为这个键存在,所以添加失败。
SETNX name wang # 添加失败
SETNX total 100 # 添加成功
SETEX
:添加一个String类型的键值对,并且指定有效期。
SETEX key seconds value
# 例:添加一个携带10s的键值对,name:wu
setex name wu 10
操作Key的层级结构的常用命令
Redis的key允许有多个单词形成层级结构,多个单词之间用 ‘:’ 隔开,格式如 项目名:业务名:类型:id
。这个格式是不固定的,可以根据自己的需求来添加或删除词条。
如果value值是一个Java对象,则可以将此对象序列化为JSON字符串存储。
KEY | VALUE |
---|---|
movie:user:1 | {“id”:1,“name”:“Tom”} |
movie:type:1 | {“id”:1,“name”:“悬疑”} |
语法:
set key value
例子:
# 存储一个JSON格式字符串的对象
set movie:user:1 '{"id":1,"name":"Tom"}'
操作Hash的常用命令
Hash类型也叫散列,其中的value是一个无序字典,类似于Java中的HashMap结构。
String结构是将对象序列化为JSON字符串后存储,当需要修改对象某个字段时很不方便。因此我们使用Hash结构可以将对象中的每个字段独立存储,可以针对单个字段做CRUD。
常见命令:
HSET
:添加或修改hash类型key的field的值。
# 这个可以添加多个
HSET key field value [field value]
# 例:添加key为movie:user:2的键,value对应的field分别为id和name,其值对应为1和Tom
HSET movie:user:2 id 1 name Tom
HGET
:获取一个hash类型key的field的值。
HGET key field
# 获取key为movie:user:2,其field为id的值。
HGET movie:user:2 id
HMSET
:批量添加hash类型key的field的值。
HMSET key field value [field value]
# 例:添加key为movie:user:3的键,value对应的field分别为id和name,其值对应为1和Tom
HSET movie:user:3 id 1 name Tom
HMGET
:批量获取多个hash类型key的field的值。
HGET key field
# 获取key为movie:user:3,其field为id和name的值。
HMGET movie:user:3 id name
HGETALL
:获取一个hash类型的key中所有的field和value的值。
HGETALL key
# 获取key为movie:user:3中所有的field和value的值。
HGETALL movie:user:3
HKEYS
:获取一个hash类型的key中所有field。
HKEYS key
# 获取key为movie:user:3中所有的field
HMGET movie:user:3
HVALS
:获取一个hash类型的key中所有value。
HVALS key
# 获取key为movie:user:3中所有的value
HVALS movie:user:3
HINCRBY
:让一个hash类型key的字段值自增并指定步长。
HVALS key field increment
# 让key为movie:user:3中的id字段增加3
HINCRBY movie:user:3 id 3
HSETNX
:添加一个hash类型的key的field的值,前提是这个field不存在,否则不执行。
HVALS key field value
# key为movie:user:3中,添加一个field为age的字段。
# 注意:如果存在,则添加失败,如果不存在,则成功。
HSETNX movie:user:3 age 15
操作List的常用命令
Redis中的List类型与Java中的LinkedList类似,可以看做是一个双向链表结构,既可以支持正向检索,也可以支持反向检索。经常用来存储一个有序数据,如朋友圈点赞列表,评论列表等。
特点:
- 有序
- 元素可以重复
- 插入和删除快
- 查询速度一般
常见命令
LPUSH
:向列表左侧插入一个或多个元素。
LPUSH key element [element ...]
# 向key为movie:user:4的列表左侧依次插入1,2,3
LPUSH movie:user:4 1 2 3
LPOP
:移除并返回列表左侧的第一个元素,没有则返回NIL。
LPOP key
# 移除key为movie:user:4的列表左侧的第一个元素
LPOP movie:user:4
RPUSH
:向列表右侧插入一个或多个元素。
RPUSH key element [element ...]
# 向key为movie:user:4的列表右侧依次插入1,2,3
RPUSH movie:user:4 4 5 6
RPOP
:移除并返回列表右侧的第一个元素,没有则返回NIL。
RPOP key
# 移除key为movie:user:4的列表右侧的第一个元素
RPOP movie:user:4
LRANGE
:返回一段角标范围内的所有元素。
LRANGE key start stop
# 返回key为movie:user的角标为 0-1的元素
LRANGE movie:user:4 0 1
BLPOP和BRPOP
:与LPOP和RPOP类似,是在没有元素时等待指定时间,而不是直接返回NIL。如果存在key,则直接返回key对应的元素。
BLPOP/BRPOP key [key...] timeout
# 注意,这里要开两个redis-cli交互控制台,否则无法完成测试
# 在第一个redis-cli交互控制台中,在key为movie:user:5的key中设置20s的等待时间
BLPOP movie:user:5 20
# 在第二个交互控制台中,向key为movie:user:5的key中向列表右侧插入 1 2 3 元素。
BPUSH movie:user:5 1 2 3
# 此时发现,在第一个redis-cli的交互控制台中出现了插入的 1 2 3元素,以及等待的时间。
思考
- 如何利用List结构模拟一个栈?
元素的入口和出口在同一边。 - 如何利用List结构模拟一个队列?
元素的入口和出口在不同边。 - 如何利用List结构模拟一个阻塞队列?
入口和出口在不同边。
出队时采用BLPOP和BRPOP。
操作Set的常用命令
Redis的Set结构与Java中的HashSet类似,可以看做是value为null的HashMap。因为也是一个hash表,它与HashSet类似的特征。
特点:
- 无序
- 元素不可重复
- 查找快
- 支持交集、并集、差集等功能。
常见命令
SADD
:向set中添加一个或多个元素。
SADD key member [member ...]
SREM
:移除set中指定元素。
SREM key member [member ...]
SCARD
:返回set中元素的个数。
SCARD key
SISMEMBER
:判断一个元素是否存在与set中。
SISMEMBER key member
SMEMBERS
:获取set中的所有元素。
SMEMBERS key
SINTER
:求key1和key2的交集。
# 创建两个set集合,分别是1,2,3,4和1,2,6,8,求它俩的交集。
SADD a 1 2 3 4
SADD b 1 2 6 8
SINTER a b
SADD
:求key1和key2的差集。
# 创建两个set集合,分别是1,2,3,4和1,2,6,8,求它的差集。
SADD a 1 2 3 4
SADD b 1 2 6 8
SDIFF a b
SUNION
:求key1和key2的并集。
# 创建两个set集合,分别是1,2,3,4和1,2,6,8,求它的并集。
SADD a 1 2 3 4
SADD b 1 2 6 8
SDIFF a b
Set命令的练习
将下列数据用Redis的Set集合来存储:
- 张三的好友有:李四.王五.赵六
- 李四的好友有:王五.麻子.二狗
利用Set的命令实现下列功能:
- 计算张三的好友有几人
- 计算张三和李四有哪些共同好友
- 查询哪些人是张三的好友却不是李四的好友
- 查询张三和李四的好友总共有哪些人
- 判断李四是否是张三的好友
- 判断张三是否是李四的好友
- 将李四从张三的好友列表中移除
代码
# 准备数据
SADD zs ls ww zl
SADD ls ww mz eg
# 计算张三的好友有几人
SCARD zs
# 计算张三和李四有哪些共同好友
SINTER zs ls
# 查询哪些人是张三的好友却不是李四的好友
SDIFF zs ls
# 查询张三和李四的好友总共有哪些人
SUNION zs ls
# 判断李四是否是张三的好友
SISMEMBER ls zs
# 判断张三是否是李四的好友
SISMEMBER zs ls
# 将李四从张三的好友列表中移除
SREM zs ls
操作SortedSet的常用命令
Redis的SortedSet是一个可排序的set集合,与Java中的TreeSet有些类似,但底层数据结构却差别很大。SortedSet中的每一个元素都带有一个score属性,可以基于score属性对元素排序,底层的实现是一个跳表(SkipList) 加hash表。因为SortedSet有可排序的特性,所以可以用来实现排行榜的功能。
特点:
- 可排序
- 元素不重复
- 查询速度快
常见命令
ZADD
:添加一个或多个元素到SortedSet ,如果已经存在则更新其score值。
ZADD key score member [score member]
ZREM
:删除SortedSet中的一个指定元素。
key member [member]
ZSCORE
:获取SortedSet中的指定元素的score。
ZSCORE key member
ZRANK
:获取SortedSet中指定元素的排名。
ZRANK key member
ZCARD
:获取SortedSet中的元素个数。
ZCARD key
ZCOUNT
:统计score值在给定范围内的所有元素的个数。
ZCOUNT key min max
ZINCRBY
:让SortedSet中的指定元素自增,步长为指定的increment的值。
ZINCRBY key increment member
ZRANGE
:按照score排序后,获取指定排名范围内的元素。
ZRANGE key min max
ZRANGEBYSCORE
:按照score排序后,获取指定score范围内的元素。
ZRANGEBYSCORE key min max
ZDIFF、ZINTER、ZUNION
:求差集、交集、并集。
ZDIFF numkeys key # 求差集
ZINTER numkeys key # 求交集
ZUNION numkeys key # 求并集
注意:所有的排名默认都是升序,如果要降序则在命令的Z后面添加REV即可。
SortedSet命令练习
将班级的下列学生得分存入Redis的SortedSet中:
jack 85,lucy 89,rose 82,tom 95,jerry 78, amy 92,miles 76。并实现下列功能:
# 准备环境
zadd class 85 jack 89 lucy 82 rose 95 tom 78 jerry 98 amy 76 miles
- 册除tom同学。
ZREM class tom
- 获取amy同学的分数。
ZSCORE class amy
- 获取rose同学的排名。
# 注意下标要从0开始
ZRANK class rose
- 查询80分以下有几个学生。
ZCOUNT class 0 80
- 给amy同学加2分。
ZINCRBY class 2 amy
- 查出成绩前3名的同学。
ZRANGE class 0 2
- 查出成绩80分以下的所有同学。
ZRANGEBYSCORE class 0 80
Redis的Java客户端
经常使用的客户端有下面几种:
Jedis:以Jedis命令作为方法名称,学习成本低,简单实用。但是Jedis实例是线程不安全的,多线程环境下需要基于连接池来使用。
lettuce:Lettuce是基于Netty实现的,支持同步、异步和响应式编程方式,并且线程是安全的。支持Redis的哨兵模式、集群模式和管道模式。
Redission:Redission是一个基于Redis实现的分布式,可伸缩的Java数据结构集合。包含了Map、Queue、Lock、Semaphore、AtomicLong等强大功能。
Jedis
使用步骤
-
引入依赖
-
创建Jedis对象,建立连接
-
使用Jedis,方法名和Redis命令一致
-
释放资源
导入下面依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.3.0</version>
</dependency>
代码实现
// 建立连接
Jedis jedis = new Jedis("192.168.31.84",6379);
// 设置密码
jedis.auth("123456");
// 这里可以选择16个库中的任意一个,注意,下标从0开始
jedis.select(1);
// 向redis中插入数据,其方法名称就是redis的命令名称
String result = jedis.set("name", "李四");
System.out.println(result);
// 获取数据
String name = jedis.get("name");
System.out.println(name);
// 释放资源
if(jedis != null){
jedis.close();
}
Jedis的连接池
Jedis本身是线程不安全的,并且频繁的创建和销毁连接会有性能损耗,因此推荐使用Jedis连接池代替Jedis的直连方式。
在数据库连接池、tomcat中的线程池等都用到了池化思想。
代码实现
public class JedisFactory {
private static final JedisPool jedisPool;
// 静态代码块:会随着类的加载而加载,确保只能执行一次,我们在加载当前这个工厂类的时候,就可以执行static的操作,完成对连接池的初始化。
static {
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(8); // 设置资源池中的最大连接数
poolConfig.setMaxIdle(8); // 设置资源池允许的最大连接数
poolConfig.setMinIdle(0); // 设置资源池确保的最少空闲连接数
poolConfig.setMaxWait(Duration.ofMillis(1000)); // 设置1000ms的等待时间
// 创建连接池对象
jedisPool = new JedisPool(poolConfig,"192.168.31.84",6379,1000,"123456");
}
// 返回连接池中的Jedis对象
public static Jedis getJedis(){
return jedisPool.getResource();
}
}
主方法
// 建立连接
Jedis jedis = JedisFactory.getJedis();
// 向redis中插入数据,其方法名称就是redis的命令名称
String result = jedis.set("name", "李四");
System.out.println(result);
// 获取数据
String name = jedis.get("name");
System.out.println(name);
// 释放资源
if(jedis != null){
jedis.close();
}
代码说明:
上边使用到了工厂设计模式来完成,我们就不需要new Jedis对象,而是使用的是连接池对象,这样直接降低了耦合。当我们使用了连接池后,当我们关闭连接其实并不是关闭,而是将Jedis还回连接池的。
SpringDataRedis
SpringData是Spring中数据操作的模块,包含了对各种数据库的集成,其中对Redis的集成模块就叫做SpringDataRedis。
- 它提供了对不同Redis客户端的整合(Lettuce和Jedis)。
- 它提供了RedisTemplate统一API来操作Redis。
- 它支持Redis的发布订阅模型。
- 它支持Redis的哨兵和Redis集群。
- 它支持基于Lettuce的响应式编程。
- 它支持JDK、JSON、字符串、Spring对象数据的序列化及反序列化。
- 它支持基于Redis的JDKCollection实现。
RedisTemplate工具类的API说明
API | 返回值类型 | 说明 |
---|---|---|
redisTemplate.opsForValue() | ValueOperations | 操作String类型的数据 |
redisTemplate.opsForHash() | HashOperations | 操作Hash类型的数据 |
redisTemplate.opsForList() | ListOperations | 操作List类型的数据 |
redisTemplate.opsForSet() | SetOperations | 操作Set类型的数据 |
redisTemplate.opsForZSet() | ZSetOperations | 操作SortedSet类型的数据 |
redisTemplate | 通用的命令 |
注意:后面使用到的StingRedisTemplate与此API很相似。只不过它里面所有类型存储的都是字符串类型的。
具体操作使用
①:导入依赖
<!-- redis依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 连接池依赖 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.6.2</version>
</dependency>
②:配置文件
spring.redis.host=192.168.31.84
spring.redis.port=6379
spring.redis.password=123456
# 最大连接数
spring.redis.lettuce.pool.max-active=8
# 最大空闲连接
spring.redis.lettuce.pool.max-idle=8
# 最小空闲连接
spring.redis.lettuce.pool.min-idle=0
# 连接等待时间
spring.redis.lettuce.pool.max-wait=100
③:代码实现
@Resource
private RedisTemplate redisTemplate;
@Test
public void testString(){
// 插入一条string类型的数据
redisTemplate.opsForValue().set("name","李四");
// 读取string类型的数据
Object name = redisTemplate.opsForValue().get("name");
System.out.println(name);
}
我们可以发现使用这种方式在redis中设置的值都是序列化后的结果。
总结:
RedisTemplate可以接收任意Object作为值写入Redis,只不过写入前会把Object序列化为字节形式,默认是采用JDK序列化。
缺点:①:可读性差。②:内存占用较大。
因此我们需要进行序列化,这里有两种序列化方式。
解决向Redis中存储数据的乱码问题
使用RedisTemplate自定义序列化的方式
默认使用的是JdkSerializationRedisSerializer序列化,现在我们改为用GenericJackson2JsonRedisSerializer序列化。
导入Jackson依赖
<!-- Jackson依赖-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
编写代码
@Configuration
public class RedisTemplateConfiguration {
@Bean
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
// 创建RedisTemplate对象
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
// 设置连接工厂
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 创建JSON序列化工具
GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
// 设置Key的序列化(strkey和HashKey)
redisTemplate.setKeySerializer(RedisSerializer.string());
redisTemplate.setHashKeySerializer(RedisSerializer.string());
// 设置value的序列化(value和hashValue)
redisTemplate.setValueSerializer(jsonRedisSerializer);
redisTemplate.setHashValueSerializer(jsonRedisSerializer);
// 返回值
return redisTemplate;
}
}
出现问题:在反序列化时知道对象的类型,JSON序列化器会将类的class类型写入json结果中,存入Redis中,会带来额外的内存开销。
使用StringRedisTemplate方式的序列化
JSON序列化器会将类的class类型写入json结果中,并且存入Redis中,这样会产生内存空间的浪费。因此,我们将不会使用JSON序列化器来处理value,而是使用String序列化器,即只能存储String类型的Key和Value。当需要存储Java对象时,手动完成对象的序列化和反序列化。
Spring提供了一个StringRedisTemplate类,它的key和value的序列化方式默认是String方式。省去了RedisTemplate的过程。
代码实现
@Resource
private StringRedisTemplate stringRedisTemplate;
private static final ObjectMapper mapper = new ObjectMapper();
@Test
public void testStringTemplate() throws JsonProcessingException {
// 准备对象
User user = new User(2, "李四");
// 准备序列化
String userJson = mapper.writeValueAsString(user);
// 向redis中添加一条数据
stringRedisTemplate.opsForValue().set("user:movie:8",userJson);
// 读取数据
String result = stringRedisTemplate.opsForValue().get("user:movie:8");
User readValue = mapper.readValue(result, User.class);
System.out.println(readValue);
}
注意:这里我们将数据写入Redis时,手动的把对象序列化为JSON格式。当读取Redis中的数据时,手动把读取到的JSON反序列化为对象。
RedisTemplate与StringRedisTemplate的不同点
不同点 | RedisTemplate | StringRedisTemplate |
---|---|---|
序列化策略不同 | 默认是JDK的序列化策略 | 采用String的序列化策略 |
具体操作类型不一样 | 可以对任意类型的key-value的键值对操作 | 只能对string类型的键值对进行操作 |
总结:如果Redis中存储的是String类型的数据,那么就使用StringRedisTemplate取数据。如果存储的是复杂类型的数据,则使用RedisTemplate取数据。
Hash类型数据的操作
代码实现
@Resource
private StringRedisTemplate stringRedisTemplate;
@Test
public void testHash(){
stringRedisTemplate.opsForHash().put("user:movie:9","id","1");
stringRedisTemplate.opsForHash().put("user:movie:9","name","李四");
Map<Object, Object> entries = stringRedisTemplate.opsForHash().entries("user:movie:9");
System.out.println(entries);
}
List类型数据的操作
代码实现
@Test
public void testList(){
stringRedisTemplate.opsForList().leftPush("list","1");
stringRedisTemplate.opsForList().leftPush("list","2");
String list = stringRedisTemplate.opsForList().leftPop("list");
System.out.println(list);
}
Set类型数据的操作
代码实现
@Test
public void testSet(){
stringRedisTemplate.opsForSet().add("set","1","2","3");
String set = stringRedisTemplate.opsForSet().pop("set");
System.out.println(set);
}
SortedSet类型数据的操作
代码实现
@Test
public void testSortedSet(){
stringRedisTemplate.opsForZSet().add("class","李明",78);
stringRedisTemplate.opsForZSet().add("class","小红",90);
stringRedisTemplate.opsForZSet().add("class","小刘",79);
Long count = stringRedisTemplate.opsForZSet().count("class", 0, 80);
System.out.println(count);
}