Redis学习笔记①基础篇_Redis快速入门


若文章内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系博主删除。


  • 资料链接https://pan.baidu.com/s/1189u6u4icQYHg_9_7ovWmA提取码eh11
  • 在线视频https://www.bilibili.com/video/BV1cr4y1671t视频合集共 175P总时长42:45:37

  • 写该系列博客的目的旨在学习巩固知识,方便个人在线阅览。
  • 博客的内容主要来自黑马程序员官方免费公开提供的资料里的文档笔记中的 PPT

  • 此外推荐一篇别人写的博客:【https://blog.gutaicheng.top/2022/08/15/Redis学习
    • 这位博主的记录的是黑马官方于 2019-11-19 BiliBili 发表的学习视频教程
      • 黑马程序员 Redis 入门到精通,深入剖析 Redis 缓存技术,Java 企业级解决方案 Redis 教程
    • 我这篇博客记录的是黑马官方于 2022-02-28 BiliBili 发表的学习视频教程
      • 黑马程序员 Redis 入门到实战教程,深度透析 Redis 底层原理 + Redis 分布式锁 + 企业解决方案 + 黑马点评实战项目

嘛,都可以看看。这个 2022 版本的有些地方讲的确实简略。

但我是懒得去看 2019 年的老视频了,不过看看别的博主记录的博客倒也是不错的选择的。


0.系列文章目录


  • 《Redis 学习笔记①基础篇_Redis 快速入门》
  • 《Redis 学习笔记②实战篇_黑马点评项目》

Redis学习笔记①基础篇_Redis快速入门_第1张图片


  • 学习目标
    • 知道 NoSQLSQL 的差别
    • 熟悉 Redis 的常用 5 种数据结构
    • 熟悉 Redis 的常用命令
    • 熟练使用 JedisSpringDataRedis

1.初识 Redis


1.1.认识 NoSQL


1.1.1.简单介绍


  • 概念NoSQLNot-Only SQL( 泛指非关系型的数据库),一般作为关系型数据库的补充。
  • 作用:应对基于海量用户和海量数据前提下的数据处理问题。
  • 特征:可扩容,可伸缩;大数据量下高性能;灵活的数据模型;高可用
  • 常见 NoSQL 数据库Redis、memcache、HBase、MongoDB

1.1.2.NoSQL 与 SQL


SQL(发音为字母 S-Q-L 或 sequel)是结构化查询语言Structured Query Language)的缩写。

SQL 是一种专门用来与数据库通信的语言。


  • SQLStructured Query Language

Redis学习笔记①基础篇_Redis快速入门_第2张图片

  • NoSQLNot-Only SQL

Redis学习笔记①基础篇_Redis快速入门_第3张图片


  • NoSQL 与 SQL 的对比表

Redis学习笔记①基础篇_Redis快速入门_第4张图片


1.2.认识 Redis


Redis 诞生于2009年全称是 Remote Dictionary Server,即远程词典服务器

Redis 是用 C 语言开发的一个开源的高性能键值对(key-value)数据库。

Redis 是一个基于内存的键值型 NoSQL 数据库


特征

  • 键值(key-value)型,value 支持多种不同数据结构,功能丰富
  • 单线程,每个命令具备原子性
  • 低延迟,速度快(基于内存、IO 多路复用、良好的编码)
  • 支持数据持久化
  • 支持主从集群、分片集群
  • 支持多语言客户端

1.3.安装 Redis


大多数企业都是基于 Linux 服务器来部署项目,而且 Redis 官方也没有提供 Windows 版本的安装包。

因此此次课程中我们会基于 Linux 系统来安装 Redis。此处选择的 Linux 版本为 CentOS 7

Redis 的官方网址https://redis.io/


1.3.1.安装 Redis 依赖


  • Redis 是基于 C 语言编写的,因此首先需要安装 Redis 所需要的 gcc 依赖
yum install -y gcc tcl

1.3.2.上传安装包并解压


  • 将课前资料提供的 Redis 安装包(redis-6.2.6.tar.gz) 上传到虚拟机的任意目录,之后进行解压操作

我这里是解压到了 /usr/local/src 目录

tar -xzf redis-6.2.6.tar.gz -C /usr/local/src
  • 进入 redis 目录之后就运行编译命令
cd redis-6.2.6/
make && make install

如果没有出错,应该就安装成功了。

默认的安装路径是在 /usr/local/bin 目录下

Redis学习笔记①基础篇_Redis快速入门_第5张图片

该目录默认配置到环境变量,因此可以在任意目录下运行这些命令。

  • redis-cli:是 redis 提供的 命令行客户端
  • redis-server:是 redis服务端启动脚本
  • redis-sentinel:是 redis哨兵启动脚本

1.3.3.Redis 默认启动


Redis 的启动方式有很多种,例如:默认启动、指定配置启动、开机自启。


安装完成后,在任意目录输入 redis-server 命令即可启动 Redis

redis-server

1.3.4.Redis 指定配置启动


如果要让 Redis 以 后台方式 启动,则必须修改 Redis 配置文件

这个就在我们之前解压的 redis 的安装包下(/usr/local/src/redis-6.2.6),名字叫 redis.conf

 cd /usr/local/src/redis-6.2.6/

在这里插入图片描述

我们先将这个配置文件备份一份

cp redis.conf redis.conf.bck

然后修改 redis.conf 文件中的一些配置(vim redis.conf

# 允许访问的地址,默认是 127.0.0.1,会导致只能在本地访问。
# 修改为 0.0.0.0 则可以在任意 IP 访问,生产环境不要设置为 0.0.0.0
bind 0.0.0.0 

# 守护进程,修改为 yes 后即可后台运行
daemonize yes 

# 密码,设置后访问 Redis 必须输入密码
requirepass 123321

Redis 的其它常见配置

# 监听的端口
port 6379

# 工作目录,默认是当前目录,也就是运行 redis-server 时的命令,日志、持久化等文件会保存在这个目录
dir .

# 数据库数量,设置为 1,代表只使用 1 个库,默认有 16 个库,编号 0~15
databases 1

# 设置 redis 能够使用的最大内存
maxmemory 512mb

# 日志文件,默认为空,不记录日志,可以指定日志文件名
logfile "redis.log"

redis.conf 中的信息是非常多的,可能不太在该文件里容易找到上述字段。

在 vim 下,可以先按住 ESC 键,之后再使用指令 / 你想要搜索的字段 查找上述字段。

配置完成之后就可以启动 redis 了(此时是按照配置文件来运行的)

redis-server /usr/local/src/redis-6.2.6/redis.conf

可以使用如下命令查看 redis 服务是否正常运行

ps -ef | grep redis

关闭 redis 服务的话,则是可以使如下命令

kill -9 查找到的服务的进程id

Redis学习笔记①基础篇_Redis快速入门_第6张图片


1.3.5.Redis 开机自启


我们也可以通过配置来实现开机自启。


首先,新建一个系统服务文件

vim /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
PrivateTmp=true

[Install]
WantedBy=multi-user.target

然后重载系统服务

systemctl daemon-reload

现在,我们可以用下面这组命令来操作 redis 了(在进行下面的操作前请先使用 kill -9 终止之前的 redis 进程)

# 启动
systemctl start redis

# 停止
systemctl stop redis

# 重启
systemctl restart redis

# 查看状态
systemctl status redis

执行下面的命令,可以让 redis 开机自启

systemctl enable redis

1.4.Redis 客户端


安装完成 Redis,我们就可以操作 Redis,实现数据的 CRUD 了。

这需要用到 Redis 客户端,包括:命令行客户端、图形化桌面客户端、编程客户端


1.4.1.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 123321:指定 Redis 的访问密码

其中的 commonds 就是 Redis 的操作命令,例如:

  • ping:与 Redis 服务端做心跳测试,服务端正常会返回 pong

不指定 commond 时,会进入 redis-cli 的交互控制台

Redis学习笔记①基础篇_Redis快速入门_第7张图片


1.4.2.图形化桌面客户端


GitHub 上的大神编写了 Redis 的图形化桌面客户端,地址:https://github.com/uglide/RedisDesktopManager

不过该仓库提供的是 RedisDesktopManager 的源码,并未提供 windows 安装包。

在下面这个仓库可以找到安装包:https://github.com/lework/RedisDesktopManager-Windows/releases

Redis学习笔记①基础篇_Redis快速入门_第8张图片


  1. 安装

在课前资料中可以找到 Redis 的图形化桌面客户端 rdm-2021.9.zip

解压缩后,运行安装程序即可安装(在 Windows 系统上操作,安装过程非常简单)

安装完成后,在安装目录下找到 rdm.exe 文件,再双击该文件即可运行

Redis学习笔记①基础篇_Redis快速入门_第9张图片


  1. 连接

点击左上角的 连接到 Redis 服务器 按钮,再在弹出的窗口中填写 Redis 服务信息

在点击”确定”按钮后,在左侧菜单会出现一个链接,点击链接即可建立连接了。

Redis学习笔记①基础篇_Redis快速入门_第10张图片


Redis 默认有 16 个仓库,编号从 0 至 15。

通过配置文件可以设置仓库数量,但是不超过 16,并且不能自定义仓库名称。

如果是基于 redis-cli 连接 Redis 服务,可以通过 select 命令来选择数据库。

# 选择 0号库
select 0

2.Redis 的常用命令


2.1.Redis 的数据结构


Redis 是一个 key-value 的数据库,key 一般是 String 类型,不过 value 的类型多种多样

Redis学习笔记①基础篇_Redis快速入门_第11张图片

Redis 的 key-value 的种类是非常多的,远远不止上面的几种类型。

Redis 为了方便我们学习,将操作不同数据类型的命令也做了分组

我们在官网( https://redis.io/commands )上可以查看到不同的命令

我们也可以在 Redis 的客户端使用 help 命令来查看相关信息(当然,官网的信息更详细)

Redis学习笔记①基础篇_Redis快速入门_第12张图片


2.2.Redis 的常用命令


通用指令是对任何数据类型都可以适用的指令。


常见的指令有:

  • KEYS:查看符合模板的所有 key(不建议在生产环境的设备上使用
  • DEL:删除一个指定的 key
  • EXISTS:判断 key 是否存在
  • EXPIRE:给一个 key 设置有效期(默认单位是秒),有效期到期时该 key 会被自动删除
  • TTL:查看一个 key 的剩余有效期(-1 代表永久有效,-2 代表 key 已经被删除)
  • 通过 help [command] 可以查看一个命令的具体用法,例如:
    Redis学习笔记①基础篇_Redis快速入门_第13张图片
    help @generic
    help @string
    help @hash
    ... ...
    

set name 123
set name1 1231
set name2 1232

get name
keys *
keys name
keys *name*
del name
exists name 
exists name1
exists name1 name2
expire age 10

ttl age

2.3.String 类型


String 类型,也就是字符串类型,是 Redis 中最简单的存储类型。

其 value 是字符串。不过根据字符串的格式不同,又可以分为 3 类:

  • string:普通字符串
  • int:整数类型,可以做自增、自减操作
  • float:浮点类型,可以做自增、自减操作
  • 不管是哪种格式,底层都是字节数组形式存储,只不过是编码方式不同。
  • 字符串类型的最大空间不能超过 512m。
KEY VALUE
msg Hello World
num 10
score 92.5

String 的常见命令有:

  • 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 不存在,否则不执行

    setnx name WangWu 效果等同于 set name WangWu nx

  • SETEX:添加一个 String 类型的键值对,并且指定有效期

    setex name 10 Jack 效果等同于 set name Jack ex 10


例1

mset test1 JoJo test2 Dio testNum 111

mget test1 testNum
incr testNum

incrby testNum 3
incrby testNum -5
set score 1.1

incrbyfloat score 0.5

get score
setnx score 1.1

setnx score2 1.2

mget score score2

思考:Redis 没有类似 MySQL 中的 Table 的概念,我们该如何区分不同类型的 key 呢?

例如这种需要 存储用户、商品信息到 redis,有一个用户 id 是 1,有一个商品 id 恰好也是 的情况。


Redis 的 key 允许有多个单词形成层级结构,多个单词之间用 : 隔开,格式如下:

项目名:业务名:类型:id

这个格式并非固定,也可以根据自己的需求来删除或添加词条。

例如我们的项目名称叫 heima,有 user 和 product 两种不同类型的数据,我们可以这样定义 key:

  • user 相关的 key:heima:user:1
  • product 相关的 key:heima:product:1

如果 Value 是一个 Java 对象,例如一个 User 对象,则可以将对象序列化JSON 字符串后存储

KEY VALUE
heima:user:1 {"id":1, "name":"Jack", "age":21}
heima:product:1 {"id":1, "name":"小米15", "price":4399}

例2

set heima:user:1 '{"id":1, "name":"Jack", "age": 21}'
set heima:user:2 '{"id":2, "name":"Rose", "age": 18}'
set heima:product:1 '{"id":1, "name":"小米11", "price": 4999}'
set heima:product:2 '{"id":2, "name":"荣耀6", "price": 2999}'

此时使用 keys * 查找所有键,发现并没有什么区别

但是使用我们之前下载过的图形化界面 RedisDesktopManager 就可以发现这种内容的键的特殊之处了

Redis学习笔记①基础篇_Redis快速入门_第14张图片


小结

  • String 类型的三种格式:字符串、int、float

  • Redis 的 key 的格式:[项目名]:[业务名]:[类型]:[id](仅供参考)


2.4.Hash 类型


Hash 类型,也叫散列,其 value 是一个无序字典,类似于 Java 中的 HashMap 结构。

String 结构是将对象序列化为 JSON 字符串后存储,当需要修改对象某个字段时很不方便。

Hash 结构可以将对象中的每个字段独立存储,可以针对单个字段做 CRUD

KEY VALUE
field value
heima:user:1 name Jack
age 21
heima:user:2 name Rose
age 18

Hash 的常见命令有:

  • 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 不存在,否则不执行

hset heima:user:3 name Lucy
hset heima:user:3 age 22

hset heima:user:3 age 33
hmset heima:user:4 name LiMei age 20 gender man
 
hmget heima:user:4 name age gender
 
hgetall heima:user:4
hkeys heima:user:4

hvals heima:user:4
hincrby heima:user:4 age 2
hsetnx heima:user:3 gender woman

2.5.List 类型


Redis 中的 List 类型与 Java 中的 LinkedList 类似,可以看做是一个双向链表结构。既可以支持正向检索和也可以支持反向检索

特征也与 LinkedList 类似:

  • 有序
  • 元素可以重复
  • 插入和删除快
  • 查询速度一般

常用来存储一个有序数据,例如:朋友圈点赞列表,评论列表等。


List 的常见命令有:

  • LPUSH key element ... :向列表左侧插入一个或多个元素
  • LPOP key移除返回列表左侧的第一个元素,没有则返回 nil
  • RPUSH key element ...:向列表右侧插入一个或多个元素
  • RPOP key移除返回列表右侧的第一个元素
  • LRANGE key star end:返回一段角标范围内的所有元素
  • BLPOPBRPOP:与 LPOPRPOP 类似,只不过在没有元素时 等待 指定时间,而不是直接返回 nil

Redis学习笔记①基础篇_Redis快速入门_第15张图片


lpush users 1 2 3

rpush users 4 5 6
lpop users 1

rpop users 1
lrange users 1 2

Redis学习笔记①基础篇_Redis快速入门_第16张图片


思考

  • 如何利用 List 结构模拟一个栈(先进后出)?
    • 入口和出口在同一边
  • 如何利用 List 结构模拟一个队列(先进先出)?
    • 入口和出口在不同边
  • 如何利用 List 结构模拟一个阻塞队列?
    • 入口和出口在不同边
    • 出队时采用 BLPOPBRPOP

2.6.Set 类型


Redis 的 Set 结构与 Java 中的 HashSet 类似,可以看做是一个 value 为 null 的 HashMap。

因为也是一个 hash 表,因此具备与 HashSet 类似的特征

  • 无序
  • 元素不可重复
  • 查找快
  • 支持 交集并集差集 等功能

String 的常见命令有

  • 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 的并集

sadd s1 a b c

smembers s1

srem s1 a

scard s1

Set 命令练习

将下列数据用 Redis 的 Set 集合来存储

  • 张三(zs)的好友有:李四、王五、赵六:sadd zs LiSi WangWu ZhaoLiu
  • 李四(ls)的好友有:王五、麻子、二狗:sadd ls WangWu MaZi ErGou

利用 Set 的命令实现下列功能

  • 计算张三的好友有几人:scard zs
  • 计算张三和李四有哪些共同好友:sinter zs ls
  • 查询哪些人是张三的好友却不是李四的好友:sdiff zs ls,输出的结果是 ZhaoLiuLiSi
  • 查询张三和李四的好友总共有哪些人:sunion zs ls
  • 判断李四是否是张三的好友:sismember zs LiSi
  • 判断张三是否是李四的好友:sismember ls ZhangSan
  • 将李四从张三的好友列表中移除:srem zs LiSi

2.7 .SortedSet 类型


Redis 的 SortedSet 是一个可排序的 set 集合,与 Java 中的 TreeSet 有些类似,但底层数据结构却差别很大。

TreeSet 的底层是基于 红黑树 来实现的。

SortedSet 中的每一个元素都带有一个 score 属性,可以基于 score 属性对元素排序,底层的实现是一个 跳表(SkipList)+ hash 表

SortedSet 具备下列特性:

  • 可排序
  • 元素不重复
  • 查询速度快

因为 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 范围内的元素
  • ZDIFFZINTERZUNION:求差集、交集、并集

注意所有的排名默认都是升序,如果要降序则在命令的 Z 后面添加 REV 即可


SortedSet 命令练习

将班级的下列学生得分存入 Redis 的 SortedSet 中

  • Jack 85, Lucy 89, Rose 82, Tom 95, Jerry 78, Amy 92, Miles 76

    ZADD stus 85 Jack 89 Lucy 82 Rose 95 Tom 78 Jerrry 92 Amy 76 Miles
    

    Redis学习笔记①基础篇_Redis快速入门_第17张图片

并实现下列功能

  • 删除 Tom 同学:ZREM stus Tom
  • 获取 Amy 同学的分数:zscore stus Amy
  • 获取 Rose 同学的排名:zrank stus Rose(升序)、zrevrank stus Rose(降序)
  • 查询 80 分以下有几个学生:zcount stus 0 80
  • 给 Amy 同学加 2 分:zincrby stus 2 Amy
  • 查出成绩前 3 名的同学:zrevrange stus 0 2
  • 查出成绩 80 分以下的所有同学:zrangebyscore stus 0 80

3.Redis 的 Java 客户端


3.1.客户端对比


在 Redis 官网中提供了各种语言的客户端,地址:https://redis.io/clients


Redis学习笔记①基础篇_Redis快速入门_第18张图片


Redis学习笔记①基础篇_Redis快速入门_第19张图片


3.1.Jedis


3.2.Jedis 入门


Jedis 使用的基本步骤

  1. 引入依赖
  2. 创建 Jedis 对象,建立连接
  3. 使用 Jedis,方法名与 Redis 命令一致

  • 项目结构我这里使用的是 Idea 软件,用 Maven 方式创建的项目

Redis学习笔记①基础篇_Redis快速入门_第20张图片


  • 导入依赖pom.xml

<dependency>
    <groupId>redis.clientsgroupId>
    <artifactId>jedisartifactId>
    <version>3.7.0version>
dependency>


<dependency>
    <groupId>org.junit.jupitergroupId>
    <artifactId>junit-jupiterartifactId>
    <version>5.7.0version>
    <scope>testscope>
dependency>

  • 具体代码src/test/java/JedisTest.java
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import redis.clients.jedis.Jedis;

import java.util.Map;

public class JedisTest {
    // 创建 Jedis 对象
    private Jedis jedis;

    @BeforeEach
    void setUp() {
        // 建立连接
        jedis = new Jedis("192.168.2.12", 6379);
        // 设置密码
        jedis.auth("123321");
        // 选择库
        jedis.select(0);
    }

    @AfterEach
    void tearDown() {
        if (jedis != null) {
            jedis.close();
        }
    }

    @Test
    void testString() {
        // 存入数据
        String result = jedis.set("name", "虎哥");
        System.out.println("result = " + result);

        // 获取数据
        String name = jedis.get("name");
        System.out.println("name = " + name);
    }

    @Test
    void testHash() {
        jedis.hset("user:1","name","Jack");
        jedis.hset("user:1","age","22");

        Map<String, String> map = jedis.hgetAll("user:1");
        System.out.println(map);
    }
}

3.2.Jedis 连接池


Jedis 本身是线程不安全的,并且频繁的创建和销毁连接会有性能损耗。

因此我们推荐大家使用 Jedis 连接池代替 Jedis 的直连方式。


src/main/java/com/heima/jedis/util/JedisConnectionFactory.java

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

public class JedisConnectionFactory {
    private static final JedisPool jedisPool;

    static {
        // 配置连接池
        JedisPoolConfig poolConfig = new JedisPoolConfig();

        poolConfig.setMaxTotal(8);
        poolConfig.setMaxIdle(8);
        poolConfig.setMaxIdle(0);
        poolConfig.setMaxWaitMillis(1000);

        //创建连接池对象
        jedisPool = new JedisPool(
                poolConfig, "192.168.150.101", 6379, 1000, "123321"
        );
    }

    public static Jedis getJedis() {
        return jedisPool.getResource();
    }
}

此时,我们便可以使用 Jedis 连接池来代替 Jedis 的直连方式了。

src/test/java/JedisTest.java

@BeforeEach
void setUp() {
    // 建立连接
    jedis = JedisConnectionFactory.getJedis();
    // ... ...
}

3.3.SpringDataRedis


3.3.1.简单介绍


SpringDataSpring 中数据操作的模块,包含对各种数据库的集成,其中对 Redis 的集成模块就叫做 SpringDataRedis

官网地址: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 通用的命令

3.3.2.RedisTemplate 快速入门


SpringBoot 已经提供了对 SpringDataRedis 的支持,使用非常简单。

  1. 引入 spring-boot-starter-data-redis 依赖
  2. application.yml 配置 Redis 信息
  3. 注入 RedisTemplate

我这里使用的是 Idea 软件,用 Spring Initializr 创建方式创建的项目,SpringBoot 的版本是 2.5.7

  • 项目结构
    Redis学习笔记①基础篇_Redis快速入门_第21张图片

  1. 引入依赖pom.xml

    
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-data-redisartifactId>
    dependency>
    
    
    <dependency>
        <groupId>org.apache.commonsgroupId>
        <artifactId>commons-pool2artifactId>
    dependency>
    
  2. 配置文件src/main/resources/application.yaml

    spring:
      redis:
        host: 192.168.150.101
        port: 6379
        password: 123321
        lettuce:
          pool:
            max-active: 8     # 最大连接
            max-idle: 8       # 最大空闲连接
            min-idle: 0       # 最小空闲连接
            max-wait: 100ms   # 连接等待时间
    
  3. 注入 RedisTemplatesrc/test/java/com/heima/RedisDemoApplicationTests.java

    @Autowired
    private RedisTemplate redisTemplate;
    
  4. 编写测试src/test/java/com/heima/RedisDemoApplicationTests.java

    @SpringBootTest
    class RedisDemoApplicationTests {
        @Autowired
        private RedisTemplate redisTemplate;
    
        @Test
        void testString() {
            // 写入一条 String 数据
            redisTemplate.opsForValue().set("name", "虎哥");
    
            // 获取 String 数据
            Object name = redisTemplate.opsForValue().get("name");
            System.out.println("name = " + name);
        }
    }
    

3.3.3.RedisSerializer


RedisTemplate 可以接收任意 Object 作为值写入 Redis。

但是 RedisTemplate 在写入前,会把 Object 序列化为字节形式,默认是采用 JDK 序列化,得到的结果是这样的:

Redis学习笔记①基础篇_Redis快速入门_第22张图片

这样会带来两个缺点:可读性差、内存占用较大。


我们可以自定义 RedisTemplate 的序列化方式,代码如下

src/main/java/com/heima/redis/config/RedisConfig.java

@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory){
        // 创建 RedisTemplate 对象
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        // 设置连接工厂
        template.setConnectionFactory(connectionFactory);
        // 创建 JSON 序列化工具
        GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
        // 设置 Key 的序列化
        template.setKeySerializer(RedisSerializer.string());
        template.setHashKeySerializer(RedisSerializer.string());
        // 设置 Value 的序列化
        template.setValueSerializer(jsonRedisSerializer);
        template.setHashValueSerializer(jsonRedisSerializer);
        // 返回
        return template;
    }
}

此外,还需要在 pom.xml 文件里加入一个新的依赖坐标


<dependency>
    <groupId>com.fasterxml.jackson.coregroupId>
    <artifactId>jackson-databindartifactId>
dependency>

此时,我们可以在 src/main/java/com/heima/redis/pojo 目录下创建一个新的 User.java 文件

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private String name;
    private Integer age;
}

当然,既然使用到了 Lombok 插件,自然又要导入新的依赖坐标

<dependency>
    <groupId>org.projectlombokgroupId>
    <artifactId>lombokartifactId>
    <optional>trueoptional>
dependency>

最后,我们可以编写一个单元测试类

src/test/java/com/heima/tests/RedisTest_1.java我自己又在 test 目录下创建了一个 tests 目录

@SpringBootTest
public class RedisTest_1 {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Test
    void testSaveUser() {
        // 写入数据
        redisTemplate.opsForValue().set("user:100", new User("虎哥", 33));

        // 获取数据
        User user = (User) redisTemplate.opsForValue().get("user:100");
        System.out.println("User 对象:" + user);
    }
}

运行测试类中的 testSaveUser() 之后的结果就是这样

Redis学习笔记①基础篇_Redis快速入门_第23张图片

为了在反序列化时知道对象的类型,JSON 序列化器会将类的 class 类型写入 json 结果中,存入 Redis,会带来额外的内存开销。


3.3.4.StringRedisTemplate


为了节省内存空间,我们并不会使用 JSON 序列化器来处理 value,而是统一使用 String 序列化器。

String 序列化器要求只能存储 String 类型的 key 和 value。

当需要存储 Java 对象时,手动完成对象的序列化和反序列化。

Redis学习笔记①基础篇_Redis快速入门_第24张图片


Spring 默认提供了一个 StringRedisTemplate 类,它的 key 和 value 的序列化方式默认就是 String 方式。

省去了我们自定义 RedisTemplate 的过程

src/test/java/com/heima/tests/RedisStringTests.java

@SpringBootTest(classes = RedisDemoApplication.class)
class RedisStringTests {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /* StringRedisTemplate 操作 String 类型 */
    @Test
    void testString() {
        // 写入一条 String 数据
        stringRedisTemplate.opsForValue().set("name", "雾山五行");
        // 获取 String 数据
        Object name = stringRedisTemplate.opsForValue().get("name");
        System.out.println("name = " + name);
    }

    /* StringRedisTemplate 操作 Object 类型 */
    private static final ObjectMapper mapper = new ObjectMapper();

    @Test
    void testSaveUser() throws JsonProcessingException {
        // 之前 redisTemplate 会帮我们自动序列化,现在需要我们自己手动序列化了

        // 创建对象
        User user = new User("吉良吉影", 33);
        // [手动-序列化]
        String json = mapper.writeValueAsString(user);
        // 写入数据
        stringRedisTemplate.opsForValue().set("user:200", json);
        // 获取数据
        String jsonUser = stringRedisTemplate.opsForValue().get("user:200");
        // [手动-反序列化]
        User user1 = mapper.readValue(jsonUser, User.class);
        System.out.println("user1 = " + user1);
    }
    
    /* StringRedisTemplate 操作 Hash 类型 */
    @Test
    void testHash() {
        stringRedisTemplate.opsForHash().put("user:400", "name", "虎哥");
        stringRedisTemplate.opsForHash().put("user:400", "age", "21");
        
        Map<Object, Object> entries = stringRedisTemplate.opsForHash().entries("user:400");
        System.out.println("entries = " + entries);
    }
}

  • RedisTemplate 的两种序列化实践方案
    • 方案一
      • 自定义 RedisTemplate
      • 修改 RedisTemplate 的序列化器为 GenericJackson2JsonRedisSerialize
    • 方案二
      • 使用 StringRedisTemplate
      • 写入 Redis 手动把对象序列化为 JSON
      • 读取 Redis 手动把读取到的 JSON 反序列化为对象

当然诸位若对 SpringDataRedis 感兴趣的话也可以看看我之前写的博客【瑞吉外卖⑩】Linux 粗略学习 & Redis 粗略学习


你可能感兴趣的:(数据库,学习,java,redis)