Redis学习笔记

文章目录

一、Redis简介

Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库[NoSQL],并提供多种语言的API
redis性能非常好,官方提供测试数据:50个并发执行10万个请求,读的速度是11万次/s,写的速度是8.1万次/s。

Redis网站:http://www.redis.net.cn/download/:下载及安装

二、Redis应用场景

  1. 缓存(数据查询、短连接、新闻内容、商品内容等)。使用最多
  2. 任务队列(秒杀、抢购、12306等)
  3. 应用排行榜
  4. 网站访问统计
  5. 数据过期处理(可以精确到毫秒)
  6. 分布式集群架构中的session分离

三、Redis安装

1. 安装redis:

  1. 下载redis ,把redis包复制到linux,如/opt/mysoft/myfile

  2. redis是c++写的,下的是redis源码包的压缩包,所以要安装c++环境
    yum install gcc-c++

  3. 解压redis包。
    tar -zxvf redis包 -C 要解压到的目录

    	## 把redis解压到 /opt/mysoft/devsoft/目录下
    	tar -zxvf redis-5.0.4.tar.gz  -C /opt/mysoft/devsoft/
    
  4. 编译和编译安装

    	## 1 进到redis解压目录
    	cd /opt/mysoft/devsoft/redis-5.0.4/
    	## 2 编译源码包(在解压目录执行make)
    	make
    	## 3 编译安装,PREFIX指定安装到的目录(安装到/usr/local/redis 目录下)
    	方法1 : make install PREFIX=/usr/local/redis
    		这里多了一个关键字 PREFIX= 这个关键字的作用是编译的时候用于指定程序存放的路径。
    		比如我们现在就是指定了redis必须存放在`/usr/local/redis`目录。
    		假设不添加该关键字Linux会将可执行文件存放在/usr/local/bin目录,
    		库文件会存放在`/usr/local/lib`目录。配置文件会存放在`/usr/local/etc`目录。
    		其他的资源文件会存放在usr/local/share目录。
    		这里指定号目录也方便后续的卸载,后续直接rm -rf /usr/local/redis 即可删除redis
    		这个解释参考<https://www.cnblogs.com/hunanzp/p/12304622.html>;【未亲测】
    	方法2:(亲测)
    		cd src  // 进到src目录(假设安装目录为 /user/local/redis
    		make install  // 执行编译安装,会将redis-server,redis-cli等安装到src目录下
    		为了方便维护,在【安装目录】新建 bin目录,并将安装的redis移动到bin目录
    		mkdir bin
    		cd src 
    		mv redis-server redis-cli redis-sentinel redis-check-aof redis-check-rdb redis-benchmark /usr/local/redis/bin
    
  5. 配置环境变量:vi /etc/profile ,添加path变量到/usr/local/redis/bin目录

    ## 1. 在/etc/profile文件中添加下面这三行
    #################REDIS_HOME##################
    export REDIS_HOME=/usr/local/redis
    export PATH=$PATH:$REDIS_HOME/bin
    
    ## 2. 重新加载配置文件
    source /etc/profile
    
  6. 配置redis-server在后台启动
    现在启动redis-server时,会在linux窗口上启动,一直占用着窗口,而不是后台启动。所以要修改redis配置,使redis服务在后台运行

    	## 1 修改redis解压目录下的redis.conf文件
    	 # 进入解压目录
    	 cd /opt/mysoft/devsoft/redis-5.0.4 
    	 # 编辑redis.conf文件。然后输入/daemonize 搜索关键字,将daemonize no 改成daemonize yes
    	 vi redis.conf  
    	 
    	## 2 将redis.conf文件 复制到 redis安装目录(也可以先复制,再改安装目录中的redis.conf文件)
    	 cp redis.conf /usr/local/redis/
    	
    	## 3 启动redis服务器端(注意:启动时要指定redis.conf配置文件)
    	 redis-server /usr/local/redis/redis.conf
    
  7. 配置redis可以被外部访问

    1. 修改redis.conf 的bind属性
      把redis.conf的bind 127.0.0.1 改为 bind 0.0.0.0,或者把bind 127.0.0.1注释掉
      在这里插入图片描述
    2. redis5 需要把保护模式关闭。把redis.conf的protected-mode yes 改为protected-mode no
      在这里插入图片描述
    3. 关闭防火墙service iptables stop

2. 启动redis

启动服务器端:

注意:必须先启动服务器端,客户端才可以连接

# 使用默认配置启动redis服务器
	redis-server
# 使用 指定配置文件 启动redis服务器
	redis-server /usr/local/redis/redis.conf  

启动客户端:(三种方式)

  1. 命令行启动客户端:redis-cli

    # 连接127.0.0.1:6379 的redis服务器端。下面这句等价于 redis-cli -h 127.0.0.1 -p 6379
    redis-cli
    
    # 连接指定redis服务器端(需要配置redis可以被外部访问,注释bind,修改protected-mode no)
    redis-cli -h ... -p 6379
    
    -h:指定访问的redis服务器的ip地址
    -p:指定访问的redis服务器的port端口
    -a:  指定登录密码(注意:修改/etc/redis.conf 下的  #requirepass foobared 去掉#,foobared 改为要设置密码,重启)
    --raw: 解决中文乱码问题
    
    
  2. 图形化界面启动客户端:
    在这里插入图片描述

  3. 使用redis的java客户端,jedis连接。
    如:注意,先jedis的包

    @Test
    public void testJedis() {
    	//创建一个Jedis的连接
    	Jedis jedis = new Jedis("127.0.0.1", 6379);
          //密码认证 如果设置了密码,就需要进行认证
    	jedis.auth("offcn123");  
    	//执行redis命令
    	jedis.set("mytest", "hello world, this is jedis client!");
    	//从redis中取值
    	String result = jedis.get("mytest");
    	//打印结果
    	System.out.println(result);
    	//关闭连接
    	jedis.close();
    	
    }
    
    

3. 退出redis

退出redis服务器端

  1. 如果在占用整个窗口模式,输入shutdown退出服务器端 或 Ctrl+C强制退出。
  2. 如果在后台服务模式,需要借助客户端退出服务器
    常用:
    # 关闭当前连接的服务器端
     redis-cli shutdown
    

退出redis客户端

  1. 输入quit
  2. 输入exit

四、Redis常用操作key的命令(客户端命令)

1、设置key的生存时间

Redis在实际使用过程中更多的用作缓存,然而缓存的数据一般都是需要设置生存时间的,即:到期后数据销毁
默认redis中的数据是永不过期。即ttl key 结果为-1

  • 设置key的生存时间(秒)EXPIRE key seconds

    EXPIRE key seconds 			设置key在seconds秒后自动删除
    如: expire key1 60   设置key1生存时间为60秒
    
  • 设置key的生存时间(毫秒)PEXPIRE key milliseconds

    PEXPIRE key milliseconds			设置key在milliseconds毫秒后自动删除
    如:	pexpire key1 1000		设置key1的生存时间为1秒,1000毫秒
    
  • 查看key的剩余生存时间TTL key

    注意:ttl如果返回值为正数(秒),表示key剩余的生存时间为该时间,如果为-1表示永久不过期,如果为-2表示是不存在的key!

    TTL key 					查看key剩余的生存时间
    如: ttl key1  查看key1剩余的生存时间
    
  • 清除生存时间(设置为永不过期):PERSIST key

    PERSIST key				清除生存时间,即取消自动删除,设置为永不过期
    如: persist key1   取消key1的生存时间,使其为永不过期
    		ttl key1   结果为:-1
    

2、获取keys(keys 命令)

keys [pattern]:如keys * 查看所有的key,keys k* 查看所有k开头的key。

3、判断key是否存在(exists 命令)

exists [key] :判断key是否存在,存在结果为1,不存在为0。可以转为java的boolean类型
exists [key ...]:判断是否存在key …,存在n条结果为n


# 产看所有的key
127.0.0.1:6379> keys *
1) "key2"
2) "key3"
3) "key1"

# 判断key2是否存在,因为存在,所以返回1.如果不存在则返回0
127.0.0.1:6379> exists key2
(integer) 1

# 判断key1 key2 key3 key4 key5 是否存在,因为只存在3条,所以返回3
127.0.0.1:6379> exists key1 key2 key3 key4 key5
(integer) 3
127.0.0.1:6379> 

4、删除key(del 命令)

del key:删除key为key的key
del key... :删除多个key的数据

# 删除 key1
127.0.0.1:6379> del key1
(integer) 1
# 判断key1是否存在。结果为0 表示不存在
127.0.0.1:6379> exists key1
(integer) 0

# 删除key1 key2 key3。结果为成功删除的条数
del key1 key2 key3 

5、重命名key (rename命令)

rename key_old key_new:将key_old的key修改为key_new

# 将key2重命名为newKey2
127.0.0.1:6379> rename key2 newKey2
OK

# 判断是否修改成功
127.0.0.1:6379> get newKey2
"value2"
127.0.0.1:6379> get key2
(nil)

6、判断key的类型(type命令)

type key:判断key的数据类型

# key1为string类型
127.0.0.1:6379> type key1
string

# key2位hash类型,相当于map
127.0.0.1:6379> type key2
hash

# key3 为list类型,列表
127.0.0.1:6379> type key3
list

# key4 为set类型,集合
127.0.0.1:6379> type key4
set

# key5 为zset类型,sortableSet
127.0.0.1:6379> type key5
zset

7、Redis的库配置与切换

redis有没有什么方法使不同的应用程序数据彼此分开同时又存储在相同的实例上呢?就相当于MySQL数据库,不同的应用程序数据存储在不同的数据库下。

7.1 库配置

redis下,数据库是由一个整数索引标识,而不是由一个数据库名称。默认情况下,一个客户端连接到数据库0。redis配置文件中下面的参数来控制数据库总数
修改/etc/redis.conf
找到:
databases 16
通过修改后面的数量可以设置库的数量。

7.2 切换到指定的库(select dbindex)

select 1    :切换到索引为1的库中,默认是在0库中
select 2    :切换到索引为2的库中

7.3 将指定的key移动到其他库(move 命令)

move key dbid:将key的数据移动到指定dbid的库中
注意:如果指定的库中已存在这个key,将移动失败

# 把key1移动到 1库中
127.0.0.1:6379> move key1 1
(integer) 1  结果为1:成功执行1条

# 切换到 1 库中,查看是否移动成功
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> keys *
1) "key1"

8、客户端中关于服务器的常用命令

8.1 测试连接是否存活(ping命令)

127.0.0.1:6379> ping
PONG               //看到这个字符串显示表示服务器存活正常

127.0.0.1:6379> ping 123
123               //原样输出ping后的字符串

8.2 在命令行打印内容(echo命令)

127.0.0.1:6379> echo zhangsan
"zhangsan"

8.3 退出连接(exit/quit)

127.0.0.1:6379> quit
127.0.0.1:6379> exit

8.4 清空当前库(flushdb命令)

flushdb    直接输入就行了,当前库的所有数据就被清空了

8.5 清空所有库(flushall命令)

flushall    直接就把所有库中的数据清空了

8.6 查看当前库中所有的key的个数(dbsize命令)

# 先获取所有的key
127.0.0.1:6379> keys *
1) "key2"
2) "key3"
3) "key5"
4) "key1"
5) "key4"

# 查看当前库中key的个数
127.0.0.1:6379> dbsize
(integer) 5

8.7 查看redis服务器信息(info命令)

# 在客户端直接输入info,就可以查看当前客户端连接的redis服务器端的信息。
# 比如版本,模式(单例,集群),连接的客户端数量...
info

# info 后可以接section,如下:只看replication部分的信息。它是有很多部分的。
info replication

9、Redis消息订阅与发布(消息队列)

注意:必须先订阅,再发布。可以同时订阅多个频道。
实际开发中基本不用redis做消息队列

  • 订阅:subscribe c1 c2
  • 发布:publish c1 'message'
  • 批量订阅:psubscribe [pattern] psubscribe a* 订阅a开头的频道

其中c表示channel:频道
具体看下边的帖子:

https://blog.csdn.net/w05980598/article/details/80444717
https://www.runoob.com/redis/redis-pub-sub.html

10、服务器命令

在/usr/local/redis/bin目录下看到:

redis-benchmark : redis性能测试工具

redis-check-aof :AOF文件修复工具

redis-check-rdb :RDB文件检查工具

redis-cli :运行Redis客户端

redis-sentinel : Redis软连接指向redis-server。sentinel:哨兵

redis-server : 运行Redis服务器端

五、Redis数据类型及基本命令

Redis中存储数据是通过key-value存储的,对于value的类型有以下5种:

  1. 字符串(string
  2. 哈希(hash
  3. 字符串列表(list
  4. 字符串集合(set)
  5. 有序字符串集合sorted set(zset
  6. stream

关于key的定义需要注意以下几点:
1、key不要太长,最好不要超过1024个字节,太长消耗内存降低查询效率
2、key不要太短,太短降低key的可读性
3、在项目中key最好有一个统一的命名规范
4、redis中的命令语句中,命令是忽略大小写的,而 key是不忽略大小写 的。

1、String字符串类型

字符串类型是Redis中最为基础的数据存储类型,它在Redis中是二进制安全的,这便意味着该类型可以接受任何格式的数据,如JPEG图像数据或Json对象描述信息等。 在Redis中字符串类型的Value最多可以容纳的数据长度是512M
在这里插入图片描述
命令:

1.1 赋值和取值:

set key value:给指定的key设置对应的value
get key:根据指定的key取出该key对应的值
mset key1 value1 key2 value2...:同时给多个键指定相应的值。(multi set)
mget key1 key2...:同时获取多个键对应的值(multi get)

# 设置(添加)key1的值为value1。如果key1存在就修改其value,如果不存在就添加key1
127.0.0.1:6379> set key1 value1
OK

# 获取key1的值
127.0.0.1:6379> get key1
"value1"

# 批量设置(添加)key的值
127.0.0.1:6379> mset key1 value11 key2 value2 key3 value3
OK

# 批量获取key的值,这是key1的值已经被修改了。
127.0.0.1:6379> mget key1 key2 key3
1) "value11"
2) "value2"
3) "value3"

1.2 取值并赋值(getset)

getset key newvalue:先将该key对应的值获取到,然后再给该key设置一个新值。(注意:本次获取的是修改之前的值)

# 获取key1的值
127.0.0.1:6379> get key1
"value11"

# 获取key1当前的值,并给他赋值为value22
127.0.0.1:6379> getset key1 value22
"value11"

# 获取key1当前的值
127.0.0.1:6379> get key1
"value22"

1.3 删除(del key)

del key:删除key为key的数据

# 删除key1,1表示成功删除了一条。
127.0.0.1:6379> del key1
(integer) 1

# 判断key1是否存在,0表示不存在
127.0.0.1:6379> exists key1
(integer) 0

1.4 value值增减(incr、decr、incrby、decrby)

  • incr key:表示给key对应的value值增加1,要求:key对应的value必须是数值类型(数字类型的string)(incr=increase:增加)
  • incrby key increment:表示给key对应的value值增加指定的幅度(结果为value+increment)。要求:key对应的value必须是数值类型
  • decr key:表示给key对应的value值减1。(decrease:减少)
  • decrby key decrement:表示给key对应的value值减少指定的幅度(结果为value-decrement)

案例:

# 添加key为num value为10的一条记录
127.0.0.1:6379> set num 10
OK

# num的value加1
127.0.0.1:6379> incr num
(integer) 11

# num的value加 5
127.0.0.1:6379> incrby num 5
(integer) 16

# num的value减1
127.0.0.1:6379> decr num
(integer) 15

# num的value减6
127.0.0.1:6379> decrby num 6
(integer) 9

1.5 拼接指定字符串到指定value(append)

append key str:将key的value后追加字符串str

127.0.0.1:6379> get key1
"hello"

127.0.0.1:6379> append key1 liming
(integer) 11   11是拼接上字符串后的总长度

127.0.0.1:6379> get key1
"helloliming"

1.6 实际应用

1.统计网站访问次数

tomcat集群指向同一条数据,每次访问都调用incr

2.生成数据表的id值

# 设置product:id 值从1开始,每次添加产品都调用incr来获取id。
# 用于纵向分表。即多个库里放同样的表,要保证每个库中的id不能重复
127.0.0.1:6379> set products:id 1
OK
127.0.0.1:6379> incr products:id
(integer) 2

2、Hash类型

Redis中的Hash类型key为String类型,value为map容器。所以该类型非常适合于存储值对象的信息。如Username、Password和Age等。如果 Hash中包含很少的字段,那么该类型的数据也将仅占用很少的磁盘空间。每一个Hash 可以存储4294967295个键值对。

存储模型如下图:key 对应 value,而value是map,也是key-value形式。为了区分,value中的key用filed(字段)代替
在这里插入图片描述

2.1 赋值

hset的时候,如果key不存在会创建相应的key,如果存在会修改这个key

  • hset key field value给某个key添加一个field-value值
  • hmset key field1 value1 field2 value2给某个key同时设置多个field-value1。(hmset=hash multi set。set多个)
  • hsetnx key field value当某个key的field不存在的时候,给它设置一个值。如果存在,不做修改。(hsetnx=hash set not exist,即设置不存在的值)
# 添加一个person:001,并设置他value的属性username为zhangsan
127.0.0.1:6379> hset person:001 username zhangsan
(integer) 1

# 添加person:002 ,并给他的value的多个字段设置值。value为map,给map赋值多个field-value。即map为{username=lisi,age=13,gender=1}
127.0.0.1:6379> hmset person:002 username lisi age 13 gender 1
OK

# 如果person:001的value不存在username字段,就添加username=zhnagsan1
# 但是person:001的value存在username,所以这次不赋值
127.0.0.1:6379> hsetnx person:001 username zhangsan1
(integer) 0

# person:001的value不存在age字段,所以设置value的age字段为15
127.0.0.1:6379> hsetnx person:001 age 15
(integer) 1

2.2 取值

  • hget key field:读取某个key的某个field值。(hash get)
  • hmget key field1 field2:同时获取某个key的多个field值。(hash multi get。即hash获取多个)
  • hkeys key:查看某个key的所有field。(hkeys=hash keys)
  • hvals key:查看某个key的所有的field对应的value。(hvals=hash values)
  • hgetall key:查看某个key所有的field及field对应的值。(hgetall=hash get all。获取所有的)
# 获取person:001的age字段的值
127.0.0.1:6379> hget person:001 age
"15"

# 获取person:001的多个字段,username字段,age字段
127.0.0.1:6379> hmget person:001 username age
1) "zhangsan"
2) "15"

# 获取person:001的value的所有的key(字段),相当于Map的keySet
127.0.0.1:6379> hkeys person:001
1) "username"
2) "age"

# 获取person:001的map的所有的value。
127.0.0.1:6379> hvals person:001
1) "zhangsan"
2) "15"

# 获取person:001的map的键和值。类似于Map的entrySet
127.0.0.1:6379> hgetall person:001
1) "username"
2) "zhangsan"
3) "age"
4) "15"

2.3 删除

  • hdel key field:删除某个key中的某个指定的field。(hash delete:即删除某个指定的filed)

  • del key:删除key及key对应的所有的field-value。(即,delete 删除某个key)

127.0.0.1:6379> hgetall person:001
1) "username"
2) "zhangsan"
3) "age"
4) "15"

127.0.0.1:6379> hdel person:001 age
(integer) 1

127.0.0.1:6379> hgetall person:001
1) "username"
2) "zhangsan"
127.0.0.1:6379> 

2.4 map的指定字段数值增加

hincrby key field increment:给某个key的指定的某个field对应的value值加指定的幅度。(hash increase:hash增加)
没有hincr,hdecr,decrby

# 给person:001的age增加5。因为person:001的age不存在,所以创建person:001的age字段,并赋值为0+5。
127.0.0.1:6379> hincrby person:001 age 5
(integer) 5

127.0.0.1:6379> hget person:001 age
"5"

2.5 判断指定的key中的filed是否存在(hexists)

hexists key field:判断指定的key中的filed是否存在,存在返回1,不存在返回0。(hash exists:hash 是否存在。即判断指定的filed是否存在)

127.0.0.1:6379> hexists person:001 age	判断user里面是否存在age这个字段
(integer) 1

2.6 获取某个key的value所包含的字段数量(hlen)

hlen key:查看指定这个key的所有field的数量。(hash length:hash的长度,即hash中的元素数量)

# 因为person:001的map只有username和age两个字段,所以结果为2
127.0.0.1:6379> hlen person:001
(integer) 2

2.7 实际应用

存储商品信息

  • 商品字段
    【商品id、商品名称、商品描述、商品库存、商品价格】

  • 定义商品信息的key
    商品1001的信息在 Redis中的key为:[products:001]


#	存储商品信息
192.168.22.132:6379> HMSET products:1001 id 3 name apple memo ‘red apple’ count 100 price 99.9
OK

# 	获取商品信息
192.168.101.3:7003> HGET products:1001 id
"3"

192.168.22.132:6379> HGETALL products:1001
 1) "id"
 2) "3"
 3) "name"
 4) "apple"
 5) "memo"
 6) "red apple"
 7) "count"
 8) "100"
 9) "price"
10) "99.9"

3、List类型(有序、可重复)

在Redis中,List类型是按照插入顺序排序的字符串链表。和数据结构中的普通链表一样,我们可以在其头部(left)和尾部(right)添加新的元素。在插入时,如果该键并不存在,Redis将为该键创建一个新的链表。与此相反,如果链表中所有的元素均被移除,那么该键也将会被从数据库中删除。List中可以包含的最大元素数量是4294967295。
从元素插入和删除的效率视角来看,如果我们是在链表的两头插入或删除元素,这将会是非常高效的操作,即使链表中已经存储了百万条记录,该操作也可以在常量时间内完成。然而需要说明的是,如果元素插入或删除操作是作用于链表中间,那将会是非常低效的。
在这里插入图片描述
注意::这里的value1、value2、value3顺序实际上反了,从左边先推进去的,实际上出现在最右边,即应该是value4,value3,value2,value1

3.1 向列表两端增加元素(lpush,rpush)

lpush key value ...: 从左边往key对应的list集合中推入多个value。(left push)
rpush key value ...:从右边往key对应的list集合中推入多个value。(right push)

# left push。从左边往链表里推,所以现在的顺序是 4,3,2,1
127.0.0.1:6379> lpush list1 value1 value2 value3 value4
(integer) 4
127.0.0.1:6379> lrange list1 0 -1
1) "value4"
2) "value3"
3) "value2"
4) "value1"

# right push。从右边往链表里推,所以顺序就是1,2,3,4
127.0.0.1:6379> rpush list2 value1 value2 value3 value4
(integer) 4
127.0.0.1:6379> lrange list2 0 -1
1) "value1"
2) "value2"
3) "value3"
4) "value4"

3.2 从列表两端弹出元素(lpop,rpop)

lpop key:表示从这个key对应的集合中最左边弹出一个元素。(left pop)

rpop key:表示从这个key对应的集合中最右边弹出一个元素。(right pop)

查看list1中所有的元素
127.0.0.1:6379> lrange list1 0 -1
1) "value4"
2) "value3"
3) "value2"
4) "value1"

# 从最左边弹出一个,可以看出来最左边的是value4,所以把value4弹出后,剩下了3,2,1
127.0.0.1:6379> lpop list1
"value4"
127.0.0.1:6379> lrange list1 0 -1
1) "value3"
2) "value2"
3) "value1"

# 从最右边弹出一个,最右边的是value1。
127.0.0.1:6379> rpop list1
"value1"
127.0.0.1:6379> lrange list1 0 -1
1) "value3"
2) "value2"

3.3 查看list中所有元素(lrange key start stop)

LRANGE命令是列表类型最常用的命令之一,获取列表中的某一片段,将返回start、stop之间的所有元素(包含两端的元素),索引从0开始。索引可以是负数,如:“-1”代表最后边的一个元素,“-2”代表倒数第二个

lrange key start stop: 查看指定的某个key对应的列表。

127.0.0.1:6379> lrange list2 0 -1
1) "value1"
2) "value2"
3) "value3"
4) "value4"

3.4 获取列表中元素的个数(llen)

llen key:查看某个key对应的集合中元素的个数(llen =》list length:list的长度,即列表中的元素个数)

# list2中有4个元素。
127.0.0.1:6379> llen list2
(integer) 4

3.5 List类型删除某个元素(lrem key count value)

lrem key count value
key:要操作的key,
count:要删除的个数,
value:要删除的值

添加8个元素
127.0.0.1:6379>  lpush list1 value1 value2 value3 value4
(integer) 4
127.0.0.1:6379>  lpush list1 value1 value2 value3 value4
(integer) 8

删除1个value1
127.0.0.1:6379> lrem list1 1 value1
(integer) 1
127.0.0.1:6379> lrange list1 0 -1
1) "value4"
2) "value3"
3) "value2"
4) "value4"
5) "value3"
6) "value2"
7) "value1"

删除2个value2
127.0.0.1:6379> lrem list1 2 value2
(integer) 2
127.0.0.1:6379> lrange list1 0 -1
1) "value4"
2) "value3"
3) "value4"
4) "value3"
5) "value1"

3.6 List类型实际应用

商品评论列表
思路:
在Redis中创建商品评论列表
用户发布商品评论,将评论信息转成json存储到list中。
用户在页面查询评论列表,从redis中取出json数据展示到页面。

# 定义商品评论列表key:
# 商品编号为1001的商品评论key【products: comment:1001】
192.168.101.3:7001> LPUSH products:comment:1001 '{"id":1,"name":"Very Goods!","date":1430295077289}'

127.0.0.1:6379> LRANGE products:comment:1001 0 -1
1) "{\"id\":1,\"name\":\"Very Goods!\",\"date\":1430295077289}"


4、Set类型(无序、不可重复)

在Redis中,我们可以将Set类型看作为没有排序的字符集合,和List类型一样,我们也可以在该类型的数据值上执行添加、删除或判断某一元素是否存在等操作。需要说明的是,这些操作的时间是常量时间。Set可包含的最大元素数是4294967295。
和List类型不同的是,Set集合中不允许出现重复的元素。和List类型相比,Set类型在功能上还存在着一个非常重要的特性,即在服务器端完成多个Sets之间的聚合计算操作,如unions、intersections和differences。由于这些操作均在服务端完成,因此效率极高,而且也节省了大量的网络IO开销。

4.1 增加/删除元素(sadd、srem)

set add 和 set remove

  • sadd key value ...:往指定key对应的集合中添加一个或多个value成员
  • srem key value ...移除指定key对应的set集合中的一个或多个value成员
# 创建key为set1的set类型数据,set的成员有member1,member2,member3。
127.0.0.1:6379> sadd set1 member1 member2 member3
(integer) 3

# 获取set1的所有成员,可以看出来是无序的
127.0.0.1:6379> smembers set1
1) "member3"
2) "member1"
3) "member2"

# 删除set1集合的member1跟member3,所以只剩下了member2
127.0.0.1:6379> srem set1 member1 member3
(integer) 2

127.0.0.1:6379> smembers set1
1) "member2"

4.2 获取set中所有的成员(smembers)

smembers key:查看某个key对应的set集合中的所有元素

 # 创建key为set1的set类型数据,set的成员有member1,member2,member3。
127.0.0.1:6379> sadd set1 member1 member2 member3
(integer) 3

# 获取set1的所有成员,可以看出来是无序的
127.0.0.1:6379> smembers set1
1) "member3"
2) "member1"
3) "member2"

4.3 判断集合(set)中是否存在指定成员(sismemeber)

sismember key value :判断指定key对应的set集合中是否含有某个value元素,有返回1,没有返回0。(sismember:set is member,即表示,是否是set集合中的成员)

# 判断set1中是否存在member2成员
127.0.0.1:6379> sismember set1 member2
(integer) 1

4.4 集合的运算(差集,交集,并集)

  • sdiff key1 key2 ...:求多个集合的差集(key1 - key2)。(sdiff=set different:不同的。表示差集。)
    在这里插入图片描述
    上图为A-B(A对B的差集),B-A 则反之

  • sinter key1 key2 ...:查看多个集合的交集。(inter=interaction:交互作用)
    在这里插入图片描述

  • sunion key1 key2 ...:求多个集合的并集(union:联盟,协会)
    在这里插入图片描述

127.0.0.1:6379> sadd A 1 2 3 4
(integer) 4
127.0.0.1:6379> sadd B 3 4 5 6
(integer) 4
127.0.0.1:6379> sadd C 1 5 6 7 8
(integer) 5

# A-B-C (A对B的差集的结果,对C的差集)
127.0.0.1:6379> sdiff A B C
1) "2"

# A-B  (A-B跟B-A是不同的差集)
127.0.0.1:6379> sdiff A B
1) "1"
2) "2"
# B-A 
127.0.0.1:6379> sdiff B A
1) "5"
2) "6"

# A∩B。AB的交集
127.0.0.1:6379> sinter A B
1) "3"
2) "4"

# A∪B。AB的并集
127.0.0.1:6379> sunion A B
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"

# A∪B∪C。ABC的并集
127.0.0.1:6379> sunion A B C
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
7) "7"
8) "8"

4.5 获取集合中成员数量(scard)

scard key:获取某个key对应的集合中元素的数量(set card。set的卡片。set的成员个数,太牵强了)

# set A的成员个数
127.0.0.1:6379> scard A
(integer) 4

# set B的成员个数
127.0.0.1:6379> scard C
(integer) 5

4.5 随机返回set集合的成员(srandmember)

srandmember key number:随机读取指定key对应的集合中的number(默认为1)个元素。(set random member:set随机成员)

# 在A集合中随机获取2个成员
127.0.0.1:6379> srandmember A 2
1) "2"
2) "1"

# 在A集合中随机获取1个成员
127.0.0.1:6379> srandmember A
"3"

5、ZSet类型(SortedSet不可重复、有序)

      Sorted-Set和Set类型极为相似,它们都是字符串的集合,都不允许重复的成员出现在一个Set中。它们之间的主要差别是Sorted-Sets中的每一个成员都会有一个分数(score)与之关联,Redis正是通过分数来为集合中的成员进行从小到大的排序。然而需要额外指出的是,尽管Sorted-Set中的成员必须是唯一的,但是分数(score) 却是可以重复的
      在Sorted-Set中添加、删除或更新一个成员都是非常快速的操作,其时间复杂度为 集合中成员数量的对数。由于Sorted-Set中的成员在集合中的位置是有序的,因此,即便是访问位于集合中部的成员也仍然是非常高效的。事实上,Redis所具有的这一特征在很多其它类型的数据库中是很难实现的,换句话说,在该点上要想达到和Redis同样的高效,在其它数据库中进行建模是非常困难的。
例如:游戏排名、微博热点话题等使用场景。

5.1 增加元素(zadd)

zadd key [NX|XX] [CH] [INCR] score member [score member ...]:前面的看不懂。反正是可以放多个 score和member,且是一一对应的。

zadd key1 score1 value1 score2 value2 score3 value3添加一个zset集合。其中value1的分数为score1 ,value2的分数score2,value3的分数score3。
注意:score在前面。member在后面。

127.0.0.1:6379> zadd zset1 10 member1 30 member2 20 member3
(integer) 3

5.2 获取指定zset中的某个成员的数值(分数)(zscore)

zscore key1 value1:查看指定的key对应集合中的某个元素的分数(score:分数)

# 添加一个zset
127.0.0.1:6379> zadd zset1 10 member1 30 member2 20 member3
(integer) 3

# 获取member1的分数
127.0.0.1:6379> zscore zset1 member1
"10"

5.3 删除指定zset中的成员(zrem)

zrem key1 value:删除指定集合的某个成员(zrem=zset remove:删除)

# 删除zset1中的member2
127.0.0.1:6379> zrem zset1 member2
(integer) 1

127.0.0.1:6379> zrange zset1 0 -1
1) "member1"
2) "member3"

5.4 按顺序排列 获取元素列表(zrange 、zrevrange)

zrange key start stop [WITHSCORES]按分数正序(低–>高)查看指定的集合中的某些元素。加了withscores就会把元素对应的score也查出来。(zset range :zset范围 在star 和stop之间)
zrevrange key start stop [WITHSCORES]按着分数反序(高–>低)查看集合中的某些元素。(zset reverse range:反序 范围,即从高到底排序获取集合中的元素)

127.0.0.1:6379> zadd zset2 20 member1 15 member2 16 member3 10 member4
(integer) 4
# 按分数升序获取zset2的所有成员(0第一个,-1倒数第一个,即最后一个)
127.0.0.1:6379> zrange zset2 0 -1
1) "member4"
2) "member2"
3) "member3"
4) "member1"

# 按分数升序获取所有成员,包括分数
127.0.0.1:6379> zrange zset2 0 -1 withscores
1) "member4"
2) "10"
3) "member2"
4) "15"
5) "member3"
6) "16"
7) "member1"
8) "20"

# 按分数降序获取所有成员
127.0.0.1:6379> zrevrange zset2 0 -1 
1) "member1"
2) "member3"
3) "member2"
4) "member4"

# 按分数降序获取所有成员及对应的分数
127.0.0.1:6379> zrevrange zset2 0 -1 withscores
1) "member1"
2) "20"
3) "member3"
4) "16"
5) "member2"
6) "15"
7) "member4"
8) "10"

5.5 zset指定的元素的分数增加(zincrby)

zincrby key increment member:给指定key的zset数据的member属性加上increment增量。

127.0.0.1:6379> zrevrange zset2 0 -1 withscores
1) "member1"
2) "20"
3) "member3"
4) "16"
5) "member2"
6) "15"
7) "member4"
8) "10"

# 给zset2的member2成员的分数加 100
127.0.0.1:6379> zincrby zset2 100 member2
"115"

5.6 zset的实际应用

商品销售排行榜
需求:根据商品销售量对商品进行排行显示
思路:定义商品销售排行榜(sorted set集合),Key为products:sellsort,分数为商品销售量。

# 写入商品销售量:
# 商品编号1001的销量是9,商品编号1002的销量是10
192.168.101.3:7007> ZADD products:sellsort 9 1001 10 1002

# 	商品编号1001的销量加1
192.168.101.3:7001> ZINCRBY products:sellsort 1 1001

# 	商品销量前10名:
192.168.101.3:7001> ZREVRANGE products:sellsort 0 9 WITHSCORES

6、Streams类型(redis5新类型、消息队列mq)

https://www.hxstrive.com/subject/redis/2056.htm

https://zhuanlan.zhihu.com/p/496944314

springboot redis streams 实现消息队列
https://gitee.com/bulkall/bulk-demo/tree/master/spring-boot-mq/spring-boot-mq-redis

六、Redis配置文件(redis.conf)

传送门!

https://blog.csdn.net/neubuffer/article/details/17003909

1. Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程
	   daemonize no
	2. 当Redis以守护进程方式运行时,Redis默认会把pid写入/var/run/redis.pid文件,可以通过pidfile指定
	   pidfile /var/run/redis.pid
	   
	3. 指定Redis监听端口,默认端口为6379
	   port 6379
	   
	4. 绑定的主机地址
	   bind 127.0.0.1
	   
	   
	5.客户端和Redis服务端的连接超时时间,默认是0,表示永不超时
	  timeout 300
	  
	6. 指定日志记录级别,Redis总共支持四个级别:debug、verbose、notice、warning,默认为notice
	  loglevel notice
	  
	7. 指定包含其它的配置文件
	  include /path/to/local.conf
	
	8.保护模式默认是开启的,如果要关闭,设置为no就可以了!
	  protected-mode yes
	  
	9.tcp-backlog
		此参数确定了TCP连接中已完成队列(完成三次握手之后)的长度, 当然此值必须不大于Linux系统定义的/proc/sys/net/core/somaxconn值,默认是511,而Linux的默认参数值是128。
		当系统并发量大并且客户端速度缓慢的时候,可以将这二个参数一起参考设定。
		
	10.tcp-keepalive
        如果值非0,单位是秒,表示将周期性的使用SO_KEEPALIVE检测客户端是否还处于健康状态,避免服务器一直阻塞,官方给出的建议值是60s。
			
	11. 日志的存储路径,默认为标准输出,如果配置Redis为守护进程方式运行,而这里又配置为日志记录方式为标准输出,则日志将会发送给/dev/null
	  logfile stdout

	12. 设置数据库的数量,默认数据库为0,可以使用SELECT <dbid>命令在连接上指定数据库id,库与库之间是隔离的!0号库中默认是带有几个键值对的,可以通过DBSIZE来查看当前数据库有几个键值对!
	   databases 16
	 
	13.requirepass foobared
	  可以设置密码
	  
	14.设置Redis连接密码,如果配置了连接密码,客户端在连接Redis时需要通过AUTH <password>命令提供密码,默认关闭
	   requirepass foobared
	   
	16. 设置同一时间最大客户端连接数,默认无限制,Redis可以同时打开的客户端连接数为Redis进程可以打开的最大文件描述符数,如果设置 maxclients 0,表示不作限制。当客户端连接数到达限制时,Redis会关闭新的连接并向客户端返回max number of clients reached错误信息
	   maxclients 100000
	   
	   
	17. 指定Redis最大内存限制,Redis在启动时会把数据加载到内存中,达到最大内存后,Redis会先尝试清除已到期或即将到期的Key,当此方法处理后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作。Redis新的vm机制,会把Key存放内存,Value会存放在swap区
	   maxmemory <bytes>

	   
	18. maxmemory-policy :当Redis的最大可用内存空间都占满时,Redis会如何处理呢?
		Redis给出了6个选项,让我们自行选择:
			volatile-lru
				使用LRU算法,从设置了过期时间的key中选择删除
			allkeys-lru
				使用LRU算法,从所有key中选择删除
			volatile-random
				从设置了过期时间的key中随机删除
			allkeys-random
				从所有的key中随机删除
			volatile-ttl
				从设置了过期时间的key中选择最先过期的删除
			noeviction
				不处理,当有写操作时,直接返回错误

			Redis的默认策略是 noeviction,配置项为 maxmemory-policy
			
			对于LRU,默认情况下Redis会采集5个key,然后从中根据LRU选择一个进行删除
			
			Redis选择5这个数,是因为5比较适中,比如选择10会很准确,但是比较耗费CUP,选择3的话会非常快,但是会降低准确度
			
			这个数可以自己配置,配置项为 maxmemory-samples,默认值是5

	
	19. 指定本地数据库文件名,默认值为dump.rdb		
         dbfilename dump.rdb
	20. 指定本地数据库存放目录
	     dir ./

注意:redis里的1k = 1000bytes 而不是1024bytes
在这里插入图片描述

七、Redis持久化(RDB、AOF)

Redis是一个支持持久化的内存数据库,也就是说redis需要经常将内存中的数据同步到磁盘来保证持久化。
redis支持二种持久化方式:

  • 1、 Snapshotting(快照)也是默认方式,这种方式也就是RDB的方式;
    在这里插入图片描述
  • 2、Append-only file(缩写aof)的方式;
    在这里插入图片描述

1、RDB持久化(将数据集快照写入磁盘)

1. 快照(RDB)是默认的持久化方式

这种方式是就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为dump.rdb。(默认存储在当前目录下,config get dir可以获得!)

2. 持久化策略(配置 自动做快照持久化)

  • 1)方式1(默认方式):我们可以配置redis在n秒内如果超过m个key被修改就自动做快照(即把redis内存中的数据持久化到dump.rdb文件中),下面是默认的快照保存配置:
    (查看redis的配置文件vi /opt/mysoft/devsoft/redis-5.0.4/redis.conf,redis.conf。/SNAPSHOTTING查找快照配置,可以看到以下内容)
    在这里插入图片描述
    解释:
		save 900 1 #900秒内如果超过1个key被修改,则发起快照保存
		save 300 10 #300秒内如超过10个key被修改,则发起快照保存
		save 60 10000 #60秒内,如超过10000个key被修改,则保存到dump.rdb文件

在这里插入图片描述
注意:rdb文件保存路径是相对于redis.conf配置文件的。

  • 2)方式2(手动保存):命令save或者bgsave及时保存:
    save:占用窗口前台保存。有可能会阻塞读写操作!
    bgsave:以后台服务方式 后台异步保存!
    shutdown :关闭服务器 也会触发将数据持久化。

3.快照(RDB)的数据恢复:

将rdb文件拷贝到redis安装目录下,正常启动就可以恢复!

运维人员:会将rdb文件做一个备份,用于恢复数据

4.优缺点:

  • 优点:
    对于相同数量的数据集而言,AOF文件通常要大于RDB文件。RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。(文件小,恢复速度快)
  • 缺点
    但是,我们可以很明显的看到,RDB有他的不足,就是一旦数据库出现问题,那么我们的RDB文件中保存的数据并不是全新的
    从上次RDB文件生成到Redis停机这段时间的数据全部丢掉了(丢失数据可能会很多。在某些业务下,这是可以忍受的,我们也推荐这些业务使用RDB的
    方式进行持久化,因为开启RDB的代价并不高。但是对于另外一些对数据安全性要求极高的应用,无法容忍数据丢失的应用,
    RDB就无能为力了,所以Redis引入了另一个重要的持久化机制:AOF日志。

2、AOF持久化(追加操作日志到指定文件)

aof日志的全称是append only file:原理是将Reids的操作日志以追加的方式写入文件,默认是 appendonly.aof

1. 开启AOF

将appendonly no 设置为appendonly yes即可!
appendfilename “appendonly.aof” 保存的文件名为:appendonly.aof
在这里插入图片描述

2. AOF的持久化策略

在Redis的配置文件中存在三种同步方式,它们分别是:

  • appendfsync always :每次有数据修改发生时都会写入AOF文件。
  • appendfsync everysec :(默认)每秒钟同步一次,该策略为AOF的缺省策略。
  • appendfsync no :从不同步。高效但是数据不会被持久化。

AOF 的默认策略为每秒钟 fsync 一次,在这种配置下,Redis 仍然可以保持良好的性能,并且就算发生故障停机,也最多只会丢失一秒钟的数据

以下也是redis.conf的APPEND ONLY MODE配置中的部分:
在这里插入图片描述

3. 修复aof文件(如果aof文件损坏了)

命令:redis-check-aof --fix appendonly.aof:修复appendonly.aof文件

由于该机制对日志文件的写入操作采用的是append模式,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容。然而如果我们本次操作只是写入了一半数据就出现了系统崩溃问题,不用担心,在Redis下一次启动之前,我们可以通过redis-check-aof工具来帮助我们解决数据一致性的问题。
如果人为在aof文件中添加其他乱七八糟的数据,也会被修复

4. 注意:当RDB和AOF同时存在的时候,AOF的优先级会高一些。

(redis配置文件(redis.conf):如果开启了AOF会在Redis启动时,加载aof文件,因为aof文件有更好的耐久度保证
在这里插入图片描述

5. 优缺点

  • 优点:Aof:持久化的频率比较高,丢失的数据比较少!
  • 缺点:AOF文件通常大于RDB文件,aof的everysec策略每秒都要同步,所以效率可能比rdb低。

3、RDB和AOF的区别

选择标准:

如果性能要求比较高,就使用RDB方式[默认的];
如果数据一致性要求比较高,就使用AOF的方式。

区别:传送门!

参考:传送门链接(redis的持久化方式RDB和AOF的区别):https://www.cnblogs.com/zxs117/p/11242026.html

八、主从复制(Replication)

1、概述:

主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master/leader),后者称为从节点(slave/follower);数据的复制是单向的,只能由主节点到从节点
默认情况下,每台Redis服务器都是主节点;且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点。

2、作用:

  • 读写分离(master用做写,slave用作读)、
  • 容灾恢复(master崩了 用slave恢复)、
  • 热备份(实时备份)、
  • 高可用基石(哨兵和集群能够实施的基础)

3、主从复制的同步方式

3.1、全量同步:

Redis全量复制一般发生在Slave初始化阶段,这时Slave需要将Master上的所有数据都复制一份。具体步骤如下:

  • 从服务器连接主服务器,发送SYNC命令;
  • 主服务器接收到SYNC命名后,开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所有写命令;
  • 主服务器BGSAVE执行完后,向所有从服务器发送快照文件,并在发送期间继续记录被执行的写命令;
  • 从服务器收到快照文件后丢弃所有旧数据,载入收到的快照;
  • 主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令;
  • 从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令;

3.2、增量同步:

Redis2.8以后,从节点可以发送 psync 命令请求同步数据,此时根据主从节点当前状态的不同,同步方式可能是全量复制或部分复制。

Redis增量复制是指Slave初始化后开始正常工作时主服务器发生的写操作同步到从服务器的过程。
增量复制的过程主要是: 主服务器每执行一个写命令就会向从服务器发送相同的写命令,从服务器接收并执行收到的写命令

4、如何使用:

4.1、开启主从复制

主从复制的开启,完全是在从节点发起的不需要我们在主节点做任何事情
从节点开启主从复制,有3种方式:

  • 配置文件:在从服务器的配置文件中加入:slaveof <masterip> <masterport>
  • 从服务器启动命令:redis-server启动命令后加入 --slaveof <masterip> <masterport>
  • 从服务器的客户端命令:Redis服务器启动后,直接通过客户端执行命令:slaveof <masterip> <masterport>,则该Redis实例成为从节点。

注意如果master设置了密码,从节点需要加入:masterauth <master-password>

4.2、断开主从复制

通过slaveof <masterip> <masterport>命令建立主从复制关系以后,可以通过slaveof no one断开。
或者把主从复制的配置删了不就完事了嘛。
从节点断开复制后,不会删除已有的数据,只是不再接受主节点新的数据变化。

4.3、模拟主从复制的具体步骤:

(因为是在同一台虚拟机上模拟的多个redis服务端,所以要修改成不同的名字跟端口号)

  • 1.配从(库)不配主(库)
  • 2.修改配置文件细节:
    1). 拷贝多个redis.conf文件
    2). 添加 daemonize yes,后台运行
    3). 修改pid文件的名字
    在这里插入图片描述
    4). 修改端口号。将port 6379 改成 port ****
    5). 修改log文件名字
    在这里插入图片描述
    6). 修改dump.rdb名字
    在这里插入图片描述
  • 3.启动主从复制。确立主从关系
    在从库的客户端,运行slaveof 主库IP 主库端口
    三种开启方式,在上边有,这是其中之一。
    注意:
    1. 每次与master断开之后,都需要重新连接,除非你配置进redis.conf文件
    2. info replication 查看当前节点的状态【主机、从机】

简单的主从复制原理总结:传送门1 : https://www.cnblogs.com/daofaziran/p/10978628.html
复杂的主从复制:传送门2 :https://www.cnblogs.com/wade-luffy/p/9639986.html

九、哨兵模式,监控(master高可用)

哨兵模式:解决master高可用问题

  1. 含义:如果master故障了,在其它的slave节点根据投票数决定由谁从 从库转换为主库

  2. 创建sentinel.conf。哨兵配置文件。
    ①.新建sentinel.conf文件,名字绝不能错(要加上所有主和从服务器)

    sentinel monitor 被监控数据库名字(自己随便起名字) 127.0.0.1 6379 1
    sentinel monitor 被监控数据库名字(自己随便起名字) 127.0.0.1 6380 1
    sentinel monitor 被监控数据库名字(自己随便起名字) 127.0.0.1 6381 1	
    

    上面最后一个数字1,表示主机挂掉后salve投票看让谁接替成为主机,得票数多少后成为主机

    ②.开启后台执行:daemonize yes

  3. 开启哨兵模式
    执行命令:redis-sentinel 哨兵配置文件,根据这个配置文件开启哨兵模式。

  4. 测试:关闭主服务器,等一会,再执行info replication查看两个从服务器的role,可以发现,待一会之后,会有一台从服务器的role变成master

配置哨兵模式:https://www.cnblogs.com/kevingrace/p/9004460.html

十、Redis事务(不重要)

1、概念

(嗐,redis事务不好使,一般不用,用spring的就够了)
和众多其它数据库一样,Redis作为Nosql数据库也同样提供了事务机制。在redis中,MULTI/EXEC/DISCARD这三个命令是我们实现事务的基石。

2、Redis事务的特征

1、在事务中的所有命令将会被串行化的顺序执行,事务执行期间,Redis不会再为其它客户端的请求提供服务,从而保证了事务中的所有命令
被原子的执行。

2、和关系型数据库中的事务相比,在Redis事务中如果有某一条命令执行失败,其后的命令仍然会被继续执行。

3、我们可以通过MULTI命令开启一个事务,对应关系型数据库中的“Begin Transaction”。在该语句之后执行的命令都将被视为事务之内的操作,最后我们可以通过EXEC/DISCARD命令来提交/回滚该事务内的所有操作。这两个Redis命令等同于关系型数据库中的COMMIT/ROLLBACK语句。

4、在事务开启之前,如果客户端与服务器端之间出现通讯故障并导致网络断开,其后所有待执行的语句都不会被服务器执行。然而如果网络中断事件是发生在客户端执行EXEC命令之后,那么该事物中的所有命令都会被服务器执行。

3、命令解释

multi:开启事务用于标记事务的开始,其后执行的命令都将被存入命令队列,直到执行EXEC时,这些命令才被原子的执行,类似于关系型数据库的begin transaction

exec:提交事务,类似于关系型数据库的:commit

discard:事务回滚,类似于关系型数据库中的rollback

4、事务提交测试

打开2个redis连接客户端

1、步骤一:在连接1,设置num 并获取数据

192.168.22.132:6379> set num 1
OK
192.168.22.132:6379> get num
"1"

2、步骤二:在连接2,num 累加1,并获取数据
192.168.22.132:6379> incr num
(integer) 2
192.168.22.132:6379> get num
"2"
3、步骤三:在连接1,获取num数据
192.168.22.132:6379> get num
"2"

4、步骤四:在连接1,开启事物,对num多次累加数据
192.168.22.132:6379> MULTI
OK
192.168.22.132:6379> INCR num
QUEUED
192.168.22.132:6379> INCR num
QUEUED
192.168.22.132:6379> INCR num
QUEUED
192.168.22.132:6379> INCR num
QUEUED
192.168.22.132:6379> INCR num
QUEUED

5、步骤五:在连接2,获取num数据
192.168.22.132:6379> get num
"2"
6、步骤六:在连接1,提交事务
192.168.22.132:6379> EXEC
1) (integer) 3
2) (integer) 4
3) (integer) 5
4) (integer) 6
5) (integer) 7

7、步骤七:在连接2,获取num数据
192.168.22.132:6379> get num
"7"

5、事务回滚测试

192.168.22.132:6379> set user jack
OK
192.168.22.132:6379> get user
"jack"
192.168.22.132:6379> MULTI      --开启事务
OK
192.168.22.132:6379> set user rose  --设置数据为rose
QUEUED
192.168.22.132:6379> DISCARD    --回滚事务
OK
192.168.22.132:6379> get user      --数据依然是jack
"jack"

6、事务失败命令测试

192.168.22.132:6379> set num 10     --初始数据是10
OK
192.168.22.132:6379> get num
"10"
192.168.22.132:6379> MULTI         --开启事务
OK
192.168.22.132:6379> INCRBY num 5  --数据加5 ,num=15
QUEUED
192.168.22.132:6379> INCRBY num x   --数据加x,抛出异常
QUEUED
192.168.22.132:6379> INCRBY num 5   --数据加5 ,num=20
QUEUED
192.168.22.132:6379> exec
1) (integer) 15
2) (error) ERR value is not an integer or out of range
3) (integer) 20       ---当提交事务的时候执行所有操作,如果部分操作异常将被忽略
192.168.22.132:6379> get num
"20"

十一、缓存击穿,穿透,雪崩

  • 缓存穿透:key对应的数据在数据源并不存在,每次针对此key的请求从缓存获取不到,请求都会到数据源,从而可能压垮数据源。比如用一个不存在的用户id获取用户信息,不论缓存还是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库。(数据库里没有,缓存也没有)
  • 缓存击穿:key对应的数据存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。(一个key的缓存过期了)
  • 缓存雪崩:当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(比如DB)带来很大压力。(多个key的缓存同时过期了)

REDIS缓存穿透,缓存击穿,缓存雪崩原因+解决方案:https://www.cnblogs.com/midoujava/p/11277096.html

redis的雪崩和穿透:https://blog.csdn.net/lzj3462144/article/details/78323589

大白话布隆过滤器:https://www.cnblogs.com/CodeBear/p/10911177.html
布隆过滤器:https://www.cnblogs.com/cpselvis/p/6265825.html

布隆过滤器:

就是一个很大的数组,存放0,1 (所以空间小,速度快),用来判断某个元素在集合中是否存在
根据hash函数,算出元素的一个hash值,然后对应数组上一个位置,位置上存储0或1。如果存在存储1,不存在存储0
判断是否存在:根据hash函数算出1个hash值,看对应位置上的数是0还是1,是1就表示可能存在,是0就肯定不存在。

如果只有一个hash函数,hash冲突可能性大,所以误差很大。所以有多个hash函数,分别计算hash值,然后对应位置存储0或1 。 判断是否存在:根据多个hash函数,算出多个hash值,看这多个值所在位置存的是0还是1,如果有一个位置是0,那肯定不存在,如果全是1,就有可能存在

十、docker部署redis

哨兵笔记:https://blog.csdn.net/BigDevil_/article/details/120765001

https://ibit.tech/archives/docker-redis-pattern
https://www.cnblogs.com/emmith/p/16466809.html#failedtryingtoloadthemastersynchronizationdbfromdisknosuchfileordirectory

集群进行故障转移的方法和Redis Sentinel进行故障转移的方法基本一样,不同的是,在集群里面,故障转移是由集群中其他在线的主节点负责进行的,所以集群不必另外使用Redis Sentinel。
(主从需要哨兵监听,集群不用,集群里由其它主节点管理实现高可用)

有几个节点就要起几个哨兵,且哨兵最好与被监听的节点不在同一个服务器。更好的是,哨兵别跟所有的redis节点放在一块,不然要挂全挂了。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
尚硅谷是一个教育机构,他们提供了一份关于Redis学习笔记。根据提供的引用内容,我们可以了解到他们提到了一些关于Redis配置和使用的内容。 首先,在引用中提到了通过执行命令"vi /redis-6.2.6/redis.conf"来编辑Redis配置文件。这个命令可以让你进入只读模式来查询"daemonize"配置项的位置。 在引用中提到了Redis会根据键值计算出应该送往的插槽,并且如果不是该客户端对应服务器的插槽,Redis会报错并告知应该前往的Redis实例的地址和端口。 在引用中提到了通过修改Redis的配置文件来指定Redis的日志文件位置。可以使用命令"sudo vim /etc/redis.conf"来编辑Redis的配置文件,并且在文件中指定日志文件的位置。 通过这些引用内容,我们可以得出结论,尚硅谷的Redis学习笔记涵盖了关于Redis的配置和使用的内容,并提供了一些相关的命令和操作示例。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Redis学习笔记--尚硅谷](https://blog.csdn.net/HHCS231/article/details/123637379)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Redis学习笔记——尚硅谷](https://blog.csdn.net/qq_48092631/article/details/129662119)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值