Redis这些知识你了解吗?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis这些知识你了解吗?相关的知识,希望对你有一定的参考价值。

Redis非关系型数据库

一、关于Redis

1.什么是NoSql?

NoSQL(NoSQL = Not Only SQL ),意即“不仅仅是SQL”,泛指非关系型的数据库.

它们都有些共同的特征:不需要预定义模式:不需要事先定义数据模式,预定义表结构。数据中的每条记录都可能有不同的属性和格式。当插入数据时,并不需要预先定义它们的模式。

弹性可扩展:可以在系统运行的时候,动态增加或者删除结点。不需要停机维护,数据可以自动迁移。

NoSQL代表MongDB、 Redis、Memcache.

2.什么是Redis?

Redis即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、“Key-Value”数据库,并提供多种语言的API;redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件。

Redis是现在最受欢迎的NoSQL数据库之一.

3.Redis的优势

当前 Redis 已经成为了主要的 NoSQL 工具,其原因如下。

1)响应快速

Redis 响应非常快,每秒可以执行大约 110 000 个写入操作,或者 81 000 个读操作,其速度远超数据库。如果存入一些常用的数据,就能有效提高系统的性能。

2)支持 8 种数据类型

它们是字符串、哈希结构、列表、集合、可排序集合, Geo 类型,基数和位图。前5种比较常用。

比如对于字符串可以存入一些 Java 基础数据类型,哈希可以存储对象,列表可以存储 List 对象等。这使得在应用中很容易根据自己的需要选择存储的数据类型,方便开发。

对于 Redis 而言,虽然只有 6 种数据类型,但是有两大好处:一方面可以满足存储各种数据结构体的需要;另外一方面数据类型少,使得规则就少,需要的判断和逻辑就少,这样读/写的速度就更快。

3)操作都是原子的

所有 Redis 的操作都是原子的,从而确保当两个客户同时访问 Redis 服务器时,得到的是更新后的值(最新值)。在需要高并发的场合可以考虑使用 Redis 的事务,处理一些需要锁的业务。

4)MultiUtility 工具

Redis 可以在如缓存、消息传递队列中使用(Redis 支持“发布+订阅”的消息模式),在应用程序如 Web 应用程序会话、网站页面点击数等任何短暂的数据中使用。

正是因为 Redis 具备这些优点,使得它成为了目前主流的 NoSQL 技术,在 Java 互联网中得到了广泛使用。

4. Redis应用场景

  • 在分布式系统中,服务器有多台,客户的请求可能会发送到不同的服务器,我们可以用redis解决多台服务器间的session共享。
  • 在高并发的情况下,所有的请求直接访问数据库,数据库容易出现异常。这个时候,就需要使用redis做一个缓冲操作,让请求先访问到redis,而不是直接访问数据库。
  • 我们在碰到需要执行耗时特别久,且结果不频繁变动的SQL,就特别适合将运行结果放入缓存。这样,后面的请求就去缓存中读取,使得请求能够迅速响应。
    具体场景
    1、会话缓存(最常用)
    2、消息队列(支付)
    3、活动排行榜或计数
    4、发布,订阅消息(消息通知)
    5、商品列表,评论列表
    6、秒杀活动,抢红包

二、 Redis的安装和配置

1.安装redis

docker-compose.yml

version: 3.0
services:
redis:
restart: always
image: daocloud.io/library/redis:5.0.9
container_name: redis
environment:
- TZ=Asia/Shanghai
ports:
- 6379:6379

2.使用Redis-cli连接Redis服务器

先进入redis容器内部:

docker exec -it 容器id bash

打开redis客户端

redis-cli

输入命令测试

Redis这些知识你了解吗?_数据库

3.使用Redis可视化管理工具连接Redis服务器

Redis Desktop Manager 是redis可视化管理工具,redi可视化客户端,redis集群管理工具。

3.1 下载和安装

https://github.com/ 网站上搜索 Redis Desktop Manager

​https://github.com/lework/RedisDesktopManager-Windows/releases​

下载以后安装,直接下一步下一步就可以。

3.2 创建连接

Redis这些知识你了解吗?_数据_02

连接成功后:

Redis这些知识你了解吗?_数据_03

三 Redis常用的5种数据类型

Redis支持的8种数据类型中前5种比较常用:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。

Redis是一个key-value形式的存储系统,key是一个“字符串”,而value对应的则是前面提到的5种数据类型

字符串(string)

这是最常见和最容易理解的一种数据类型,它表示存储在redis中的值是一个“字符串”类型的数据。但实际上,它还能存储整型数据,后面我们将通过​​INCR​​命令,对值进行自增操作。

哈希(hash)

又称“散列”,这种数据类型类似于Java中的Map类型。初学者可能会疑惑,前面的“字符串”类型,一个key一个value不就是Map类型么。

实际上,在本文开头提到,redis是一种key-value形式的存储系统,我们所说的redis数据类型指的是value的数据类型。所以哈希(hash)也就是value是类似Map的一种数据类型。在后面的章节中我们会更直观的感受到。

列表(list)

列表(list)也可以理解为数组,和在Java中的List类型类似。略微不同的是,Java中的列表可以是泛型类型,也就是说Java中的List数据结构可以是字符串、整型等。而在redis中列表中的数据类型则只有字符串类型。

集合(set)

set类型在redis中被称为集合,同样它和Java的Set集合相同。和redis的列表(list)类似,不同地是,列表(list)的数据是可以重复的且是插入有序,而集合(set)中的数据是不可重复的且是无序。

有序集合(zset)

有序集合(zset)尽管看起来是集合(set)类型多了“有序”的特性。但实际上,可以说它和哈希(hash)更相似。因为它和哈希(hash)一样也是Map类型,不同地是它的key是实际上的成员,而value则是用于排序的“分值”。这个特性能帮助我们快速的实现“点赞数最高倒序排列”等功能。

四 Redis常用命令

1.Redis 字符串(String) 常用命令

1.set

set uname daimenglaoshi   #存值

#set key value
  1. get
get uname   #取值

#get key
  1. mset
mset sex m age 23   #批量存值

#mset key1 value1 key1 value1...

4.mget

mget sex age  #批量取值

#mget key1 key2

5.自增

incr age    #age中的值自增1

#incr key

incrby age 3 #age中的值自增3

#incrby key increment
  1. 自减、
decr age    #age中的值自减1

#decr key

decrby age 3 #age中的值自减3

#decrby key increment
  1. Setnx
exists city  #是否存在key city

setnx city shanghai #如果不存在city,则可以赋值,如果存在,则赋值失败

#setnx key value

8.Setex

Setex 命令为指定的 key 设置值及其过期时间。如果 key 已经存在, SETEX 命令将会替换旧的值

setex message 60   hello  # 设置message=hello  保存时间60秒

#setex key seconds value

2.Redis 哈希(Hash) 常用命令

  1. hset
hset goods name  huawei   #存数据

#hset key field value
  1. hget
hget goods name   #取数据

#hget key field
  1. hmset
hmset goods name huawei  price 3000 #批量存储数据

#hmset key field vlue field2 value2
  1. hmget
hmget goods name price   #批量取数据

#hmget key field1 field2

5.hincrby

hincrby goods price 100  # 增量   正数为+   负数为-

#hincrby key field increment
  1. hexists
hexists goods name   #判断字段是否存在

#hexists key field
  1. hsetnx
hsetnx goods num 100   #给不存在的字段赋值 如果字段已存在 赋值失败

#hsetnx key field value
  1. hkeys
hkeys goods   #返回某个对象所有的字段名

#hkeys key
  1. hvals
hvals goods   #返回某个对象所有的字段值

#hvals key

3.Redis 列表(List) 命令

  1. 存储数据
lpush list1 aa  #列表左边添加一个值  也可以添加多个值

rpush list1 cc #列表右边添加一个值 也可以添加多个值
  1. 取出数据
lpop list1   #移除并返回列表左边第一个元素

rpop list1 #移除并返回列表右边第一个元素
  1. 列表存在才存储
lpushx list1 bb   # list1存在 则左边添加一个bb

rpushx list1 dd # list1存在 则右边添加一个dd
  1. 获取指定索引范围的数据
lrange list1 0 -1   # 获取列表中所有元素  0代表第一个元素  -1 代表最后一个元素   

#lrange list begin end
  1. 通过索引获取指定元素
lindex list1 0   # 返回下标为0的元素  

#lindex list index
  1. 给指定位置赋值
lset list1 0 aa    #设置集合list1的第一个元素为aa

#lset list index value
  1. 返回列表的长度
llen list1   #返回列表的长度

#llen list
  1. 在指定位置插入数据
linsert list1 before bb  ee   #在bb前面添加一个ee

#linsert key BEFORE | AFTER pivot value
  1. 对列表修剪
ltrim list 1 -1    #只保留列表中第2到最后的元素

#ltrim list begin end
  1. Rpoplpush
rpoplpush list1 list2   #将list1的最后一个元素弹出 并添加到list2的左边
  1. Brpoplpush
brpoplpush list1 list2  2  #将list1的最后一个元素弹出 并添加到list2的左边 如果没有元素 则等待2秒

#Brpoplpush 命令从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。

4.Redis 集合(Set) 命令

  1. sadd 添加数据
sadd myset user1,user2,user3   #添加数据 也可以添加多个

#sadd set value1 value2 。。
  1. 返回元素
smembers myset    #返回所有数据

srandmember myset #随机返回一个元素,此元素还在集合中

srandmember myset #随机返回两个元素
  1. spop 随机移除数据
spop myset   #随机移除一个元素

spop myset 2 #随机移除两个元素
  1. srem 删除指定数据
srem myset user1 #移除集合中的一个或多个成员元素,不存在的成员元素会被忽略
  1. scard 返回集合的数量
scard myset1  返回集合的数量
  1. smove 移动数据
smove myset1 myset2 user1   #将myset1中的user1移动到myset2中
  1. sinter 交集
sinter myset1 myset2  #返回myset1和myset2的交集
  1. sunion 并集
sunion myset1 myset2   #返回myset1和myset2的并集
  1. sdiff 差集
sdiff myset1 myset2   #返回myset1和myset2的差集

5.Redis 有序集合(sorted set) 命令

  1. 添加数据
zadd accessset 1 aa.com  #添加数据 设置分数为1

#zadd set score value score value。。
  1. 取数据
zrange accessset 1 3 withscores  #返回下标1--3之间的元素和分数  位置按分数从小到大

zrange accessset 0 -1 withscores #返回整个集合 按分数递增

zrevrange accessset 0 -1 withscores #返回整个集合 按分数递减

zrangebyscore accessset 1 100 # 返回分数在1到100之间的数据

zrangebyscore accessset 1 100 withscores #返回分数在1到100之间的数据和分数

zrangebyscore accessset 1 100 withscores limit 0 1 #返回分数在1到100之间的数据和分数的前1个

zrangebyscore accessset -inf +inf withscores #返回全部数据

zrevrangebyscore accessset 1 100 #降序返回分数在1到100之间的数据
  1. 移除数据
zrem accessset aa.com bb.com    #移除有序集中的一个或多个成员,不存在的成员将被忽略
  1. 增加分数
zincrby accessset 2 aa.com    #将aa.com的分数增加2
  1. 返回指定元素的分数
zscore accessset bb.com   #返回bb.com的分数
  1. 返回指定元素的排名
zrank accessset aa.com   #返回aa.com的排名   0代表第一

#有序集成员按分数值递增(从小到大)顺序排列
  1. 返回集合的数量
zcard accessset   返回集合中元素的数量

6.Keys常用命令

  1. 查看key
keys  *    #查看所有的key
keys u* #查看所有u开头的key

keys pattern
  1. 查看某一个key是否存在
exists uname
  1. 删除key
del uname
  1. 修改key的名称
rename id uid  # 修改key的名称id为uid

#rename oldkey newkey #在集群模式下,key 和newkey 需要在同一个 hash slot。key 和newkey有相同的 hash tag 才能重命名
  1. 设置key的过期时间
expire uname  20  # 设置key为name的过期时间为20秒

#expire key_name seconds #设置key的过期时间
  1. 返回key的过期时间
ttl uname   #返回uname的过期时间

#ttl key_name #返回指定key的过期时间 时间单位为秒

#pttl key_name #返回指定key的过期时间 时间单位为毫秒
  1. 删除指定key的过期时间
persist uname   #删除uname的过期时间
  1. 移动key到指定数据库
数据库有0-15,默认是使用数据库0
可以用select选择数据库
move uname 1 #将数据库0中的uname移动到数据库1

select 1 #使用数据库1

exists uname #查看数据库1是否有uname
  1. 返回key中值得类型
type uname  #返回uname中值的类型 可返回string,hash,list,set,zset等

7.Redis发布/订阅命令

除了使用List实现简单的消息队列功能以外,Redis还提供了发布订阅的消息机制。在这种机制下,消息发布者向指定频道(channel)发布消息,消息订阅者可以收到指定频道的消息,同一个频道可以有多个消息订阅者.

Redis也提供了一些命令支持这个机制.

  1. 发布消息
publish my_channel "hello"    #给频道my_channel发布消息

#publish channe_name msg #用于将消息发送到指定的频道 返回的接收到消息的订阅者数量
  1. 订阅消息
subscribe my_channel   #从my_channel频道中订阅消息

#subscribe channel_name 返回结果包含返回值的类型(订阅成功)、订阅的频道名称、目前已订阅的频道数量
  1. 取消订阅
unsubscribe my_channel  #取消my_channel频道的消息订阅

#unsubscribe channel_name #取消一个或多个频道的订阅
  1. 按模式订阅消息
psubscribe channel:*   #订阅所有以channel开头的频道
  1. 按模式取消订阅
punsubscribe channel:*  #取消订阅所有以channel开头的频道
  1. 查询活跃频道
pubsub channels      #查询至少有一个订阅者的频道
  1. 查看频道订阅数
pubsub numsub my_channel  #查看my_channel频道的订阅数

五 Java和Redis的交互

Jedis是Redis官方首选的Java客户端开发包,库文件实现了对redis各类API进行封装调用。

5.1 使用Jedis连接Redis

Jedis直连相当于一个TCP连接,数据传输完成后关闭连接。

1.创建springboot项目
2.导入相关依赖包
<!-- lombok 包-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 默认的测试包不是junit 需要移除默认的测试包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 加入junit 包-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- redis client-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.0.0</version>
</dependency>

Redis这些知识你了解吗?_redis_04

3.创建测试类测试

Redis这些知识你了解吗?_redis_05

Redis这些知识你了解吗?_数据_06

Redis这些知识你了解吗?_redis_07

4.String类型的命令应用场景

案例1:计数

如微博的评论数、点赞数、分享数,抖音作品的收藏数,京东商品的销售量、评价数等。

Redis这些知识你了解吗?_redis_08

案例2:存对象

对于属性值不常改变的对象,可以将对象转换成json字符串,再存储在string类型中,是个不错的选择,如用户信息、商品信息等。

创建user类:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User

private int id;

private String name;

private int age;

导入fastjson依赖:

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.15</version>
</dependency>

测试:

Redis这些知识你了解吗?_数据库_09

5.hash类型的命令应用场景

案例1:用hash存购物车信息

Redis这些知识你了解吗?_数据库_10

案例2:用hash存对象

存储对象可以用String命令,将对象转换为字节数组或json字符串,也可以用Hash命令。

当对象的属性不需要频繁修改时,可以选择用String方式。

当对象的某个属性需要频繁修改时,不适合用string+json,因为它不够灵活,每次修改都需要重新将整个对象序列化并赋值,如果使用hash类型,则可以针对某个属性单独修改,没有序列化,也不需要修改整个对象。比如,商品的价格、销量、关注数、评价数等可能经常发生变化的属性,就适合存储在hash类型里。

但是,当对象的某个属性不是基本类型或字符串时,使用hash类型就必须手动进行复杂序列化。非常麻烦。

所以可以选择:一般对象用string存储,对象中某些频繁变化的属性抽出来用hash存储。

Redis这些知识你了解吗?_数据库_11

6.list类型的命令应用场景

list类型是简单的字符串列表,按照插入顺序排序。

list可以用来做消息队列,排行榜,最新评论列表,最新点赞列表等,不过后面有专门的rabbitMQ等消息队列中间件,redis中的list主要是用来做排行榜和最新列表之类。

案例:排行榜

list类型的lrange命令可以分页查看队列中的数据。可将每隔一段时间计算一次的排行榜存储在list类型中,如商品销量排行、成绩排名等。

但是,并不是所有的排行榜都能用list类型实现,只有定时计算的排行榜才适合使用list类型存储,与定时计算的排行榜相对应的是实时计算的排行榜,list类型不能支持实时计算的排行榜,之后在介绍有序集合sorted set的应用场景时会详细介绍实时计算的排行榜的实现。

//list类型存排行榜
@Test
public void testList()

//1.创建连接对象
Jedis jedis=new Jedis("42.192.12.30",6379);

//2.操作
jedis.lpush("rankinglist","zhongxing");
jedis.lpush("rankinglist","xiaomi");
jedis.lpush("rankinglist","vivo");
jedis.lpush("rankinglist","huawei");

List<String> list=jedis.lrange("rankinglist",0,2);

for(String s:list)
System.out.println(s);

//3.关闭连接
jedis.close();

Redis这些知识你了解吗?_数据库_12

案例2:

list类型的lpush命令和lrange命令能实现最新列表的功能,每次通过lpush命令往列表里插入新的元素,然后通过lrange命令读取最新的元素列表,如朋友圈的点赞列表、评论列表。

但是,并不是所有的最新列表都能用list类型实现,因为对于频繁更新的列表,list类型的分页可能导致列表元素重复或漏掉,举个例子,当前列表里由表头到表尾依次有(E,D,C,B,A)五个元素,每页获取3个元素,用户第一次获取到(E,D,C)三个元素,然后表头新增了一个元素F,列表变成了(F,E,D,C,B,A),此时用户取第二页拿到(C,B,A),元素C重复了。只有不需要分页(比如每次都只取列表的前5个元素)或者更新频率低(比如每天凌晨更新一次)的列表才适合用list类型实现。对于需要分页并且会频繁更新的列表,需用使用有序集合sorted set类型实现。另外,需要通过时间范围查找的最新列表,list类型也实现不了,也需要通过有序集合sorted set类型实现,如以成交时间范围作为条件来查询的订单列表。之后在介绍有序集合sorted set类型的应用场景时会详细介绍sorted set类型如何实现最新列表。

//list类型存最新列表  如评论列表
@Test
public void testList2()

//1.创建连接对象
Jedis jedis=new Jedis("42.192.12.30",6379);

//2.操作
jedis.lpush("commentlist","不错");
jedis.lpush("commentlist","牛b");
jedis.lpush("commentlist","很好");
jedis.lpush("commentlist","棒棒的");

List<String> list=jedis.lrange("commentlist",0,-1);

for(String s:list)
System.out.println(s);
jedis.lpop(s);


//3.关闭连接
jedis.close();

Redis这些知识你了解吗?_数据库_13

7.set类型的命令应用场景

集合类型的元素的特点是唯一且无序。

案例1:好友列表

可以用它存储好友列表

sinter获取两个用户的共同好友,scard可以获取好友数量。

//set  存放好友列表
@Test
public void testSet1()

//1.创建连接对象
Jedis jedis=new Jedis("42.192.12.30",6379);

//2.操作
//A的好友
jedis.sadd("friendsA:list","aa","bb","cc");
//B的好友
jedis.sadd("friendsB:list","bb","cc","dd");

//查看共同好友
Set<String> innerSet=jedis.sinter("friendsA:list","friendsB:list");
for(String s:innerSet)
System.out.println(s);


//3.关闭连接
jedis.close();

Redis这些知识你了解吗?_数据库_14

案例2:随机展示,抽奖

网站或app首页展示推荐时,可以提前选一批需要展示的内容,然后从中随机选取一部分展示。

//set  抽奖
@Test
public void testSet2()

//1.创建连接对象
Jedis jedis=new Jedis("42.192.12.30",6379);
//2.操作
// 所有用户列表
jedis.sadd("user:list","aa","bb","cc","dd");

//随机抽取一人 抽完此人还在集合中
String luckUser=jedis.srandmember("user:list");
System.out.println(luckUser);
System.out.println("---------------------");

//随机抽取两人
List<String> luckList=jedis.srandmember("user:list",2);

//查看集合中所有元素
Set<String> usersSet=jedis.smembers("user:list");
for(String s:usersSet)
System.out.println(s);
System.out.println("---------------------");

//随机抽取1人 抽完将他移除
String luckUser2=jedis.spop("user:list");
System.out.println(luckUser2);
System.out.println("---------------------");

//随机抽取两人 抽完将他们移除
Set<String> luckList2= jedis.spop("user:list",2);

//查看集合中所有元素
Set<String> usersSet2=jedis.smembers("user:list");
for(String s:usersSet)
System.out.println(s);
//3.关闭连接
jedis.close();

8.zset类型的命令应用场景

前面我们用list做过排行榜,但不是所有的排行榜都能用list类型实现,只有定时计算的排行榜才适合使用list类型存储,与定时计算的排行榜相对应的是实时计算的排行榜,实时排行榜可以用zset来实现。

比如:热点新闻排行,直播打赏排行等。

也可以用在需要排序的列表,比如 关注列表,粉丝列表等。

案例:热点新闻排行榜

//zset  排行榜
@Test
public void testZset()

//1.创建连接对象
Jedis jedis=new Jedis("42.192.12.30",6379);

jedis.flushDB();//清空数据库
//2.操作
jedis.zadd("hotnews",1000,"新闻1"); //score存放点击数
jedis.zadd("hotnews",2000,"新闻2");
jedis.zadd("hotnews",1500,"新闻3");
jedis.zadd("hotnews",1800,"新闻4");
jedis.zadd("hotnews",2500,"新闻5");

//查询点击数前3的新闻
Set<String> set= jedis.zrevrange("hotnews",0,2);
for(String s: set)
System.out.println(s);
System.out.println("-------------------");

//查询点击数前3的新闻和对应的点击数
Set<Tuple> set2= jedis.zrevrangeWithScores("hotnews",0,2);
for (Tuple t : set2)
System.out.println(t.getElement() + ":" + t.getScore());

//3.关闭连接
jedis.close();

Redis这些知识你了解吗?_数据_15

5.2 使用 Jedis连接池

采用jedis直连方式,每次都需要创建连接对象和关闭对象,我们可以使用之前学过的线程池概念,采用jedis连接池。使用Jedis线程池可以不需要创建新的Jedis对象连接Redis,可以大大减少对于创建和回收Redis连接的开销。

1 使用连接池
@Test
public void testPool()

//1.创建连接池 采用默认配置 连接池中的redis预先定义好
JedisPool jedisPool=new JedisPool("42.192.12.30",6379);


//2.从连接池中获取jedis对象
Jedis jedis=jedisPool.getResource();

//3.使用jedis
String val=jedis.get("aa");
System.out.println(val);

//4.释放jedis到连接池
jedis.close();;

2 设置连接池的配置信息
@Test
public void testPool2()

//1.创建连接池配置信息
GenericObjectPoolConfig poolConfig=new GenericObjectPoolConfig();

poolConfig.setMaxTotal(50); //连接池最大连接数 默认是8

poolConfig.setMaxIdle(50); //允许的最大空闲数 默认是8 建议MaxTotal=MaxIdle

poolConfig.setMinIdle(2); //最小空闲数 默认是0

// 当连接池中资源用尽时,调用者的最大等待时间(毫秒)
//默认是-1 表示永不超时,不建议使用默认值,这样会消耗大量时间
poolConfig.setMaxWaitMillis(1000);

//2.创建连接池 采用默认配置 连接池中的redis预先定义好
JedisPool jedisPool=new JedisPool(poolConfig,"42.192.12.30",6379);

//3.从连接池中获取jedis对象
Jedis jedis=jedisPool.getResource();

//4.使用jedis
String val=jedis.get("aa");
System.out.println(val);

//5.释放jedis到连接池
jedis.close();;

5.3 使用SpringBoot配置连接池信息

在实际开发中,配置信息应该从代码中提出,放在单独的配置文件中,这样不用每次使用时都需要配置,也便于之后修改配置信息.

在application.propertis文件中加入:

jedis.pool.host=42.192.12.30
#Redis服务器连接端口
jedis.pool.port=6379
jedis.pool.config.maxTotal=50
jedis.pool.config.maxIdle=50
jedis.pool.config.minIdle=2
jedis.pool.config.maxWaitMillis=1000

如果使用的是yml格式则为:

jedis:
pool:
host: 42.192.12.30
port: 6379
config:
maxTotal: 50
maxIdle: 50
minIdle: 2
maxWaitMillis: 1000
注意:yml基本格式要求:

1.大小写敏感;
2.使用缩进代表层级关系;
3.缩进只能使用空格,不能使用tab键,不要求空格个数,只需要相同层级左对齐(一般2或4个空格)。

配置项格式为key: value,冒号后要有一个空格:

创建RedisConfiguration类,将配置文件信息注入进来

package com.example.testjedis.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;


@Configuration
public class RedisConfiguration

@Autowired
@Qualifier("jedis.pool.config")
private JedisPoolConfig jedisPoolConfig;

@Bean(name= "jedis.pool")
public JedisPool jedisPool(@Value("$jedis.pool.host")String host,
@Value("$jedis.pool.port")int port)
return new JedisPool(jedisPoolConfig, host, port);


@Bean(name= "jedis.pool.config")
public JedisPoolConfig jedisPoolConfig (@Value("$jedis.pool.config.maxTotal")int maxTotal,
@Value("$jedis.pool.config.maxIdle")int maxIdle,
@Value("$jedis.pool.config.minIdle")int minIdle,
@Value("$jedis.pool.config.maxWaitMillis")int maxWaitMillis)
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(maxTotal);
config.setMaxIdle(maxIdle);
config.setMaxWaitMillis(maxWaitMillis);
return config;


创建代码测试:

@RestController
public class TestController

@Autowired
private JedisPool jedisPool;

@RequestMapping("testRedisPool")
public String testRedisPool()

Jedis jedis= jedisPool.getResource();

jedis.set("name","aa");

String val=jedis.get("name");

return val;

Redis这些知识你了解吗?_数据_16

六、设置Redis访问权限

1.设置配置文件路径

docker-compose.yml

ersion: 3.0
services:
redis:
restart: always
image: daocloud.io/library/redis:5.0.9
container_name: redis
environment:
- TZ=Asia/Shanghai
ports:
- 6379:6379
volumes:
- ./redis/redis.conf:/usr/local/etc/redis/redis.conf
command: ["redis-server","/usr/local/etc/redis/redis.conf"]

2.配置文件中设置密码

在redis目录下创建redis.conf文件

redis.conf文件中添加:

requirepass daimenglaoshi  #设置访问密码

3.Jedis连接时需要设置密码

jedis.auth("密码");

作业:springboot整合jedisPool 加密码

七、批量处理多条命令

1. 使用管道

在某些高并发的场景下,网络开销成了Redis速度的瓶颈,所以需要使用管道技术来实现突破。

每个命令的执行时间 = 客户端发送时间+服务器处理和返回时间+一个网络来回的时间

那么如果有多个命令要一起执行,我们可以放入管道,一起发送过去,节约网略来回的时间。

但管道操作会消耗一定的内存,所以管道中命令的数量并不是越大越好(太大容易撑爆内存),而是应该有一个合理的值。

另外管道中某些指令失败,管道也会继续执行。所以不适合存放后面需要前面结果的命令。

//测试不用管道执行一万次命令
@Test
public void test()

//1.创建连接池 采用默认配置 连接池中的redis预先定义好
JedisPool jedisPool=new JedisPool("42.192.12.30",6379);

//2.从连接池中获取jedis对象
Jedis jedis=jedisPool.getResource();

long begin=System.currentTimeMillis();
jedis.set("count","1");
//3.使用jedis
for(int i=1;i<=10000;i++)
jedis.incr("count");

long end=System.currentTimeMillis();

System.out.println("执行时间:"+(end-begin)); //82312

//4.释放jedis到连接池
jedis.close();




//测试用管道执行一万次命令
@Test
public void test2()

//1.创建连接池 采用默认配置 连接池中的redis预先定义好
JedisPool jedisPool=new JedisPool("42.192.12.30",6379);

//2.从连接池中获取jedis对象
Jedis jedis=jedisPool.getResource();

//3.创建管道
Pipeline pipeline=jedis.pipelined();

long begin=System.currentTimeMillis();
jedis.set("count","1");
//4.将命令加入管道
for(int i=1;i<=10000;i++)
pipeline.incr("count");

//5.执行管道中的命令
pipeline.syncAndReturnAll();

long end=System.currentTimeMillis();
System.out.println("执行时间:"+(end-begin));//485

//6.释放jedis到连接池
jedis.close();;

2.使用事务

redis事务提供了一种“将多个命令打包, 然后一次性、按顺序地执行”的机制, 并且事务在执行的期间不会主动中断 —— 服务器在执行完事务中的所有命令之后, 才会继续处理其他客户端的其他命令。

redis事务使用了multi、exec、discard、watch、unwatch命令。

2.1.执行事务

Redis这些知识你了解吗?_数据_17

2.2取消事务

Redis这些知识你了解吗?_数据库_18

2.3 事务中有语法错误

若在事务队列中存在语法性错误,则执行exec命令时,其他正确命令会被执行,错误命令抛出异常。

Redis这些知识你了解吗?_数据_19

2.4 事务中出现命令错误

若在事务队列中存在命令性错误,则执行exec命令时,所有命令都不会执行。

Redis这些知识你了解吗?_redis_20

2.5 watch监听

watch命令用于在事务开始之前监视任意数量的键: 当调用exec命令执行事务时, 如果任意一个被监视的键已经被其他客户端修改了, 那么整个事务不再执行, 直接返回失败。没有改变则正常执行事务。

Redis这些知识你了解吗?_数据_21

Redis这些知识你了解吗?_数据_22

3.使用lua脚本

Lua是一个小巧的脚本语言,一般用于嵌入式应用,现在越来越多应用于游戏当中,魔兽世界,愤怒的小鸟都有用到。

Lua极易嵌入到其他程序,可当做一种配置语言。还可以应用到很多需要性能的地方,比如:游戏脚本,nginx,redis的脚本

互联网应用场景:

Nginx + lua 开发高性能web应用,限流、防止sql注入、请求过滤,黑白名单限制等等等。

redis + lua  实现原子操作,避免多线程数据不一致的问题
3.1设置脚本对应的数据卷

修改docker-compose.yml文件,添加脚本对应的数据卷

version: 3.0
services:
redis:
restart: always
image: daocloud.io/library/redis:5.0.9
container_name: redis
environment:
-- TZ=Asia/Shanghai
ports:
- 6379:6379
volumes:
- ./redis/redis.conf:/usr/local/etc/redis/redis.conf
- ./redis/lua/:/usr/local/etc/redis/lua #添加lua文件对应的数据卷
command: ["redis-server","/usr/local/etc/redis/redis.conf"]

重新执行docker-compose

docker-compose down
docker-compose up -d
3.2.在lua数据卷目录下创建lua文件

1.lua文件内容如下:

local key=KEYS[1]

local value=ARGV[1]

local key2=KEYS[2]

local value2=ARGV[2]

redis.call("set",key,value);

redis.call("set",key2,value2);
3.3.执行lua文件

进入到redis容器

docker exec -it 容器id  bash

执行lua脚本文件

redis-cli --eval /usr/local/etc/redis/lua/1.lua  name age , aa 18
# redis-cli --eval lua文件路径 key1 key2 , value1 value2
# redis-cli -a 密码 --eval lua文件路径 key1 key2 , value1 value2
#注意 key和value之间的逗号前后要有空格

Redis这些知识你了解吗?_redis_23

八、Redis持久化机制

redis是一个内存数据库,数据保存在内存中,如果突然宕机,数据就会全部丢失。因此必须有一种机制来保证 Redis 的数据不会因为故障而丢失,这种机制就是 Redis 的持久化机制。

Redis 的持久化机制有两种,第一种是RDB快照(Redis DataBase),第二种是 AOF 日志(Append Only File)。

1.RDB快照

1.1 RDB快照优缺点

RDB其实就是把数据以快照的形式保存在磁盘上。什么是快照呢,你可以理解成把当前时刻的数据拍成一张照片保存下来。

RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘。也是默认的持久化方式,这种方式是就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为dump.rdb。

优点

  • RDB文件小,非常适合定时备份,用于灾难恢复
  • Redis加载RDB文件的速度比AOF快很多,因为RDB文件中直接存储的是内存数据,而AOF文件中存储的是一条条命令,需要重演命令。

缺点

  • RDB无法做到实时持久化,若在两次bgsave间宕机,则会丢失区间(分钟级)的增量数据,不适用于实时性要求较高的场景
  • 每次保存RDB的时候,Redis都要fork()出一个子进程,并由子进程来进行实际的持久化工作。在数据集比较庞大时,fork()可能会非常耗时,造成服务器在某某毫秒甚至1秒内停止处理客户端
  • 存在老版本的Redis不兼容新版本RDB格式文件的问题
1.2 使用RDB方式实现持久化

修改redis.conf,添加配置信息

Redis这些知识你了解吗?_数据_24

添加数据卷,对应保存的快照文件目录

Redis这些知识你知道吗?

你真的懂Redis的5种基本数据结构吗?这些知识点或许你还需要看看(图文并茂,浅显易懂,建议收藏)

你真的懂Redis的5种基本数据结构吗?

面试吃透了这些Redis知识点,面试官一定觉得你很NB(干货 | 建议珍藏)

面试官:你对Redis缓存了解吗?面对这11道面试题你是否有很多问号?

面试官:你对Redis缓存了解吗?面对这11道面试题你是否有很多问号?