Redis学习笔记

Redis

第一部分 简介

1.nosql 数据库

2.redis有16个数据库,默认使用0号数据库

3.redis是单线程+多路IO复用,支持持久化,以及支持多种数据类型

4.memcached是多线程+锁,支持单一数据类型

5.redis有五种数据类型

6.redis基于key-value存储

第二部分 Redis运行基础

1. 安装
2. Redis基础命令

在linux安装成功后,/usr/local/bin 会出现以下命令

redis-benchmark 性能测试工具,可以运行测试一下自己笔记本的性能

redis-check-aof 修复有问题的aof文件

redis-check-rdb 修复有问题的rdb文件

redis-sentinel redis集群使用

redis-server 启动redis服务

redis-cli 进入客户端

3. Redis后台服务

redis一般使用后台服务启动所以要修改配置文件

配置文件在 /opt/redisxxxx/ 下 redis.conf

一般情况下会复制一份到etc下 然后修改etc下的配置文件

cp redis.conf /etc/redis.conf

vim /etc/redis.conf

搜索daemonize no 将no改为yes

4. 启动

cd /usr/local/bin

redis-server /etc/redis.conf

可通过ps -ef | grep redis 查看进程

5. 客户端连接

redis-cli -h localhost -p 6379

如果连接不上,或其他问题看看防火墙是否关闭

(本机连接不上)

检查防火墙状态

systemctl status firewalld

systemctl stop firewalld

6. 关闭

1.直接在里面shutdown

2.kill -9 uid

3.先exit推出redis 然后 redis-cli shutdown

第三部分 Redis数据类型及语法

key键(非数据类型)

因为redis基于key-value存储所以对key的操作至关重要

1.keys *

查看本库所有key

keys *
1) "myzset"
2) "String"
3) "mylist"
4) "myhash"
5) "myset"
2.exists key

查看是否存在该key

存在返回(integer)1

没有返回(integer)0

exists myset
(integer) 1
3.type key

获取key类型

type mylist
list
4.del key

删除key,直接删除

5.unlink key

删除key,不直接删除

直接返回删除成功,后续通过异步操作完成删除

6.expire key 10

为已存在的key设置有效时间“秒”

时间结束后key会删除

expire time 100
(integer) 1
7.ttl key

查看key的有效时间

(integer)-1 永久有效

(integer)-2 已过期

(integer)x 还有x秒过期

ttl time
(integer) 74
ttl myset
(integer) -1
ttl no
(integer) -2
8.flushdb

清除库

9.flushall

清除全部库

String

String是Redis最基本的数据类型,一个key对应一个value

value最大512M。

String是二进制安全的,也就是说可以存放,图片二进制,以及序列化的对象

String的底层是一个简单的动态字符串,类似java的ArrayList,通过预分配空间的方式节省空间。当超过1M是每次最多增加1M

1.添加key

1.set key value

创建一个String类型的数据

多次添加同一个key的值,会覆盖前value

set String stringvalue
OK

2.mset key1 value1 key2 value2 …

一次创建多个key-value

mset string1 value1 string2 value2
OK

3.setnx key value

和set不同的是,如果该key已经存在,那就不会在设置值

setnx string1 value1
(integer) 0
setnx string3 value3
(integer) 1

4.msetnx key1 value1 key2 value2 …

一次添加多个key-value ,重复则不再设置

5.setex key x value

添加一个有期限的key-value ,如果key存在,直接覆盖

2.获取value

1.get key

获取对应的value

get string1
"value1"

2.mget key1 key2

一次获取多个value

mget string1 string2
1) "value1"
2) "value2"

3.getrange key star end

例:getrange k1 0 2

获取指定value的指定长度,角标从0开始

getrange string1 0 3
"valu"
3.修改value

1.appen key value

追加

对当前key的value进行追加,返回追加后的长度

127.0.0.1:6379> get string1
"value1"
127.0.0.1:6379> append string1 123
(integer) 9
127.0.0.1:6379> get string1
"value1123"

2.incr key

对数字类型的value进行+1

如果该key不存在那么,会自动创建key并赋值为1

127.0.0.1:6379> set number 100
OK
127.0.0.1:6379> get number
"100"
127.0.0.1:6379> incr number
(integer) 101

3.incrby key 步长

对数字类型的value进行+步长操作

127.0.0.1:6379> set number 101
OK
127.0.0.1:6379> get number
"101"
127.0.0.1:6379> incrby number 100
(integer) 201

4.decr key

对数字类型的value-1

127.0.0.1:6379> get number
"201"
127.0.0.1:6379> decr number
(integer) 200

5.decrby key 步长

对数字类型的value进行-步长操作

6.setrange key star value

覆盖指定value指定位置以及之后n位的值,索引从0开始

127.0.0.1:6379> set name jack
OK
127.0.0.1:6379> get name
"jack"
127.0.0.1:6379> setrange name 2 mark
(integer) 6
127.0.0.1:6379> get name
"jamark"

7.getset key value

以新值换旧值

返回指定key原来的value,将现在的value赋值给key

127.0.0.1:6379> get string1
"value1123"
127.0.0.1:6379> getset string1 change
"value1123"
127.0.0.1:6379> get string1
"change"
4.strlen key

返回当前key的长度

List

list是一个双向链表,所以在查询是效率很高,并且有序(放入顺序和取出顺序一样)。

1.添加key

lpush/rpush key value1 value2 …

创建list

也可以用来添加value,在该list左/右边添加一个value

添加方向不同,初始value的顺序也会不同

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"

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"

2.获取value

1.lrange key star end

获取指定key指定位置的value

0 表示左边第一个元素

-1表示右边第一个元素

所以0 -1是所有元素

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

2.lindex k1 x

获取指定key指定位置的value

角标从0开始

127.0.0.1:6379> lindex list2 2
"value3"
3.修改value

1.lpop/rpop

取出左/右第一个value,相当于删除

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

2.linsert key before/after value newvalue

在指定value前/后插入newvalue

127.0.0.1:6379> lrange list1 0 -1
1) "value3"
2) "value2"
3) "value1"
127.0.0.1:6379> linsert list1 after value2 value0.5
(integer) 4
127.0.0.1:6379> lrange list1 0 -1
1) "value3"
2) "value2"
3) "value0.5"
4) "value1"

3.lrem key x value

从左向右删除x个value值 0表示删除全部

127.0.0.1:6379> lrange list1 0 -1
1) "value0.5"
2) "value2"
3) "value3"
4) "value2"
5) "value0.5"
6) "value1"
127.0.0.1:6379> lrem list1 1 value2
(integer) 1
127.0.0.1:6379> lrem list1 0 value0.5
(integer) 2
127.0.0.1:6379> lrange list1 0 -1
1) "value3"
2) "value2"
3) "value1"

4.rpoplpush key1 key2

取出key1右边第一个值放到key2左边

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

//一番操作将list2右边第一个取出放到list1左边
llen key

获取指定key的value长度

Set

set集合,是一个无序集合(放入顺序和取出顺序不一样)且元素不重复,放入元素后它会根据hashcode进行元素排序。

底层是一个Hash表,key放元素,value为null,所以元素不能重复

1.添加key

sadd key value1 value2 …

创建/添加集合元素

127.0.0.1:6379> sadd set1 value1 value2 value3 //创建
(integer) 3
127.0.0.1:6379> smembers set1
1) "value3"
2) "value2"
3) "value1"
127.0.0.1:6379> sadd set1 value4  //添加
(integer) 1
127.0.0.1:6379> smembers set1
1) "value3"
2) "value4"
3) "value2"
4) "value1"

2.获取value

smembers key

获取指定集合的全部元素

127.0.0.1:6379> sadd set1 value1 value2 value3
(integer) 3
127.0.0.1:6379> smembers set1
1) "value3"
2) "value2"
3) "value1"

srandmember key n

从指定key中随机获取n个value不删除

127.0.0.1:6379> srandmember set1
"value3"
127.0.0.1:6379> srandmember set1
"value4"
127.0.0.1:6379> srandmember set1
"value3"
3.修改value

1.srem key value …

删除指定key的指定value,可以一次删除多个元素

127.0.0.1:6379> smembers set1
1) "value3"
2) "value4"
3) "value2"
4) "value1"
127.0.0.1:6379> srem set1 value1
(integer) 1
127.0.0.1:6379> smembers set1
1) "value3"
2) "value4"
3) "value2"

2.spop key

从指定key中随机吐出一个value(删除)

127.0.0.1:6379> smembers set1
1) "value3"
2) "value4"
3) "value2"
127.0.0.1:6379> spop set1
"value2"
127.0.0.1:6379> spop set1
"value4"
127.0.0.1:6379> smembers set1
1) "value3"
4.多集合操作

1.smove key1 key2 value

将key1中的value移到key2中

127.0.0.1:6379> smembers set1
1) "value3"
2) "value2"
3) "value1"
127.0.0.1:6379> smembers set2
1) "value3"
2) "value5"
3) "value4"
127.0.0.1:6379> smove set1 set2 value1   //移动
(integer) 1
127.0.0.1:6379> smembers set1
1) "value3"
2) "value2"
127.0.0.1:6379> smembers set2
1) "value3"
2) "value5"
3) "value1"
4) "value4"

2.sinter key1 key2

取两集合的交集

127.0.0.1:6379> smembers set1
1) "value3"
2) "value2"
3) "value1"
127.0.0.1:6379> smembers set2
1) "value3"
2) "value5"
3) "value4"
127.0.0.1:6379> sinter set1 set2
1) "value3"

3.sunion key1 key2

取两集合的并集

127.0.0.1:6379> smembers set1
1) "value3"
2) "value2"
3) "value1"
127.0.0.1:6379> smembers set2
1) "value3"
2) "value5"
3) "value4"
127.0.0.1:6379> sunion set1 set2
1) "value3"
2) "value5"
3) "value1"
4) "value2"
5) "value4"

4.sdiff key1 key2

取两集合的差集

key1中有,key2中没有

127.0.0.1:6379> smembers set1
1) "value3"
2) "value2"
3) "value1"
127.0.0.1:6379> smembers set2
1) "value3"
2) "value5"
3) "value4"
127.0.0.1:6379> sdiff set1 set2
1) "value1"
2) "value2"

5.sismember key value

判断是否含有某元素

含有返回(integer)1

不包含返回(integer)0

127.0.0.1:6379> sismember set1 value1
(integer) 0
127.0.0.1:6379> sismember set1 value2
(integer) 1 
6.scard key

返回指定集合的长度

Hash

hash的存储非常特殊,如图所示:

在这里插入图片描述

所以这种类型非常适合存储对象

Hsah底层数据少时是ziplist(压缩列表)数据多时是hashtable

判断条件为

  • 当哈希类型元素个数小于hash-max-ziplist-entries配置(默认512个)
  • 所有值都小于hash-max-ziplist-value配置(默认64字节
1.添加key

1.hset key field1 value1 field2 value2…

可以说是存储一个对象,多添加表示覆盖

127.0.0.1:6379> hset user1 id 1 name lll age 10
(integer) 3
127.0.0.1:6379> hgetall user1
1) "id"
2) "1"
3) "name"
4) "lll"
5) "age"
6) "10"

2.mhset key field1 value1 field2 value2…

可以一次存储多个hash,但是一般就使用hset就行了

3.hsetnx key field value

设置一个非存在字段

127.0.0.1:6379> hgetall user1
1) "id"
2) "1"
3) "name"
4) "lll"
5) "age"
6) "10" 
127.0.0.1:6379> hsetnx user1 name ggg  //存在存储失败
(integer) 0
127.0.0.1:6379> hsetnx user1 address m //不存在设置成功
(integer) 1

2.获取value

1.hget key field

获取指定field的value

127.0.0.1:6379> hget user1 name
"lll"
127.0.0.1:6379> hget user1 id
"1"

2.hmget key field1 field2…

一次获取多个value

127.0.0.1:6379> hmget user1 id name age address
1) "1"
2) "lll"
3) "10"
4) "m"

3.hvals key

获取指定key的所有value

127.0.0.1:6379> hvals user1
1) "1"
2) "lll"
3) "10"
4) "m"

4.hgetall key

获取指定key所有的 field 和value

127.0.0.1:6379> hgetall user1
1) "id"
2) "1"
3) "name"
4) "lll"
5) "age"
6) "10"
7) "address"
8) "m"

3.修改value

1.hdel key field

删除指定key的field

127.0.0.1:6379> hkeys user1
1) "id"
2) "name"
3) "age"
4) "address"
127.0.0.1:6379> hdel user1 address
(integer) 1
127.0.0.1:6379> hkeys user1
1) "id"
2) "name"
3) "age"

2.hincrby key field x

为指定field +x 命令带by,就表示带步长

127.0.0.1:6379> hget user1 age
"10"
127.0.0.1:6379> hincrby user1 age 10  //操作修改
(integer) 20
127.0.0.1:6379> hget user1 age
"20"

3.hset key field value

重新设置覆盖,也可以添加

127.0.0.1:6379> hgetall user1
1) "id"
2) "1"
3) "name"
4) "lll"
5) "age"
6) "20"
127.0.0.1:6379> hset user1 age 10   //操作修改
(integer) 0
127.0.0.1:6379> hgetall user1
1) "id"
2) "1"
3) "name"
4) "lll"
5) "age"
6) "10"

4.hexists key field

判读是否存在某个字段

127.0.0.1:6379> hkeys user1
1) "id"
2) "name"
3) "age"
127.0.0.1:6379> hexists user1 id
(integer) 1
127.0.0.1:6379> hexists user1 address
(integer) 0
5.hkeys key

获取指定key的所有字段

127.0.0.1:6379> hkeys user1
1) "id"
2) "name"
3) "age"
6.hlen key

获取指定key的字段长度

7.hstrlen key field

获取指定key指定field的value长度

127.0.0.1:6379> hkeys user1
1) "id"
2) "name"
3) "age"
127.0.0.1:6379> hstrlen user name
(integer) 4

Zset

zset和set特性基本一致,不过他是个有序集合。

底层也是hash 一个key对应多个value

一个value分为 score value

该集合会根据score将各个元素进行从大到小的排序

此外在hash的基础上添加跳跃表

1.添加key

1.zadd key score1 value1 score2 value2 …

添加/创建一个Zset集合

127.0.0.1:6379> zadd language 1 c 5 c++ 10 java 20 php 100 python
(integer) 5
127.0.0.1:6379> zrange language 0 -1
1) "c"
2) "c++"
3) "java"
4) "php"
5) "python"
2.获取value

1.zrange key star end

通过索引值获取value

127.0.0.1:6379> zrange language 0 -1
1) "c"
2) "c++"
3) "java"
4) "php"
5) "python"

2.zrevrange key star end

通过倒序索引获取value

127.0.0.1:6379> zrange language 0 -1
1) "c"
2) "c++"
3) "java"
4) "php"
5) "python" 
127.0.0.1:6379> zrevrange language 0 -1  //倒序查询
1) "python"
2) "php"
3) "java"
4) "c++"
5) "c"

3.zrangebyscore key star end

通过score获取指定区间的value

127.0.0.1:6379> zrangebyscore language 0 10
1) "c"
2) "c++"
3) "java"
127.0.0.1:6379> zrangebyscore language 0 100
1) "c"
2) "c++"
3) "java"
4) "php"
5) "python"

127.0.0.1:6379> zrangebyscore language (1 100  //做不包含写法
1) "c++"
2) "java"
3) "php"
4) "python"

3.删除value

1.zrem key value

删除删除指定value

127.0.0.1:6379> zrange language 0 -1
1) "c"
2) "c++"
3) "java"
4) "php"
5) "python"
127.0.0.1:6379> zrem language java   //删除
(integer) 1
127.0.0.1:6379> zrange language 0 -1
1) "c"
2) "c++"
3) "php"
4) "python"

2.zremrangebyscore key star end

通过score删除指定区间内的value

127.0.0.1:6379> zrange language 0 -1
1) "c"
2) "c++"
3) "php"
4) "python"
127.0.0.1:6379> zremrangebyscore language 5 50  //删除执行
(integer) 2
127.0.0.1:6379> zrange language 0 -1
1) "c"
2) "python"

3.zremrangebyrank key star end

通过索引删除指定区间内的value

127.0.0.1:6379> zrange language 0 -1
1) "c"
2) "c++"
3) "java"
4) "php"
5) "python"
127.0.0.1:6379> zremrangebyrank language 0 3  //删除
(integer) 4
127.0.0.1:6379> zrange language 0 -1
1) "python"
4.获取score

1.zscore key value

通过value获取对应的score

127.0.0.1:6379> zscore language python
"100"

2.zincrby key x value

增减指定value的score

127.0.0.1:6379> zscore language python
"100"

127.0.0.1:6379> zincrby language  100 python //执行操作
"200"
127.0.0.1:6379> zscore language python
"200"

5.获取索引/数量

1.zrank key value

通过value获取该value的索引

127.0.0.1:6379> zrange language 0 -1
1) "c++"
2) "java"
3) "php"
4) "python"
127.0.0.1:6379> zrank language java
(integer) 1

2.zrevrank key value

获取指定value在集合中倒序索引

127.0.0.1:6379> zrange language 0 -1
1) "c++"
2) "java"
3) "php"
4) "python"
127.0.0.1:6379> zrank language java  //正序
(integer) 1

127.0.0.1:6379> zrevrank language java  //倒序
(integer) 2

3.zcount key score_star score_end

通过score获取指定区间的value个数

127.0.0.1:6379> zcount language 5 50
(integer) 3

4.zcard key

获取该集合中的元素个数

127.0.0.1:6379> zcard language 
(integer) 4
127.0.0.1:6379> zrange language 0 -1
1) "c++"
2) "java"
3) "php"
4) "python"

Bitmaps

bitmaps是一个可以对位操作的数据类型,底层是一个字符串,不过他有一套特定的命令用于操作。
在这里插入图片描述

只能0/1存储。这种方式非常适合存放,比如,用户是否上线等数据。长度很长。

1.setbit key index 0/1

添加/创建key

index 表示偏移量 就是在value中的位置

127.0.0.1:6379> setbit user3 2 1
(integer) 0
127.0.0.1:6379> setbit user3 10 1
(integer) 0
1.getbit key index

获取指定偏移位上的0/1

127.0.0.1:6379> getbit user3 1
(integer) 0
127.0.0.1:6379> getbit user3 2
(integer) 1

3.bitcount key star end

0 -1 代表所有 分区按照字节来分,也就是一个区8位

0 0 表示 1-8位中有几个1

0 -1 表示全部所有有几个1

127.0.0.1:6379> bitcount user3 0 -1
(integer) 2
127.0.0.1:6379> bitcount user3 0 0
(integer) 1

HyperLolgLog

主要用于计数,没别的用处元素不重复

1.pfadd key value1 value2…
127.0.0.1:6379> pfadd program java c c++
(integer) 1
127.0.0.1:6379> pfadd program python mysql
(integer) 1
127.0.0.1:6379> pfadd program java		//重复添加失败
(integer) 0

2.pfcount key

统计个数

127.0.0.1:6379> pfcount program
(integer) 5
3.pfmerge key/newkey key1 key2

合并两个key 可以合并到已存在的key,也可以合并到newkey

127.0.0.1:6379> pfcount language
(integer) 3
127.0.0.1:6379> pfcount program
(integer) 5
127.0.0.1:6379> pfmerge program language  //合并  
OK
127.0.0.1:6379> pfcount program
(integer) 8

Geospatial

用来存储地理位置

底层是Zset,所以类型就是Zset

key对应一组城市

value包含两个字段 维度(经度纬度) 城市名

1.geoadd key 经度 纬度 name

添加/创建key 可以同时添加多个

127.0.0.1:6379> geoadd china:city 121.47 31.23 shanghai
(integer) 1
127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqing 114.05 22.52 shenzhen
(integer) 2

2.geopos key name

通过name获取指定的经度纬度

只能获取已有的

127.0.0.1:6379> geopos china:city zhengzhou  //不存在的城市
1) (nil)
127.0.0.1:6379> geopos china:city shanghai
1) 1) "121.47000163793563843"
   2) "31.22999903975783553"
127.0.0.1:6379> geopos china:city shanghai shenzhen
1) 1) "121.47000163793563843"
   2) "31.22999903975783553"
2) 1) "114.04999762773513794"
   2) "22.5200000879503861"

3.geodist key name1 name2 company

通过经纬度计算两地的直线距离

单位有

m km fm(英尺) mi(英里)

127.0.0.1:6379> geodist china:city shanghai shenzhen m
"1215922.3698"
127.0.0.1:6379> geodist china:city shanghai shenzhen km
"1215.9224"
4.georaduis key 经度 维度 raduis conpany

定点搜索周围城市

127.0.0.1:6379> georadius china:city 110 30 1000 km
1) "chongqing"
2) "shenzhen"

第四部分 Redis配置文件

1. NETWORK 网络配置

重要

​ 1.bind 127.0.0.1 -::1 绑定本机;表示只能本地访问;一般注掉

​ 2.protected-mode yes 保护模式;只能本机访问;一般改为no

​ 3.port 6379 端口号

​ 4.tcp-backlog 511 tcp链接队列

​ 5.timeout 0 连接超时时间,0代表永不超时。

​ 6.tcp-keepalive 300 心跳检测时间

2. GENERAL 常见配置

重要

​ 1.daemonize yes 是否开启 后台启动服务

​ 2.pidfile /var/run/redis_6379.pid 进程号

​ 3.loglevel notice 日志级别

​ 4.logfile “” 日志文件位置,默认不保存

​ 5.databases 16 默认数据库个数

3. SNAPSHOTTING 持久化RDB

重要

​ 1.stop-writes-on-bgsave-error yes 当磁盘无法写入时是否停止redis写操作

​ 2.dbfilename dump.rdb 默认持久化文件名字

​ 3.dir ./ 持久化存储的路径 ./ 代表当前路径,也就是启动目录

​ 4.rdbcompression yes 持久化文件是否需要压缩,redis使用L2F算法

​ 5.rdbchecksum yes 持久化完整性检查;持久化前redis会使用CRC64算法进行校验,会有10%的性能消耗

​ 6.save 保存频率,手动进行(一般不用);save 300 100 300s检测一下如果有100个key变化那就持久化

4. APPEND ONLY MODE 持久化AOF

重要

​ 1.appendonly no 是否开启aof持久化模式

​ 2.appendfilename “appendonly.aof” 持久化文件名

​ 3.appendfsync always/everysecno 同步日志的频率 时刻同步/每秒同步/让操作系统决定同步(跟自己的情况而定)

​ 4.no-appendfsync-on-rewrite no 重写时是否要使用 appendfsync

​ 5.auto-aof-rewrite-percentage 100 设置重写时文件大小 阈值

​ 6.auto-aof-rewrite-min-size 64mb 设置重写最小文件的大小

5. REDIS CLUSTER 集群

​ 1.cluster-enabled yes 开启集群,默认是注掉的

​ 2.cluster-config-file nodes-6379.conf 集群节点名称

​ 3.cluster-node-timeout 15000 连接超时时间

10. 配置模块概述
  • REPLICATION 复制配置

  • SECURITY 安全设置

    可以设置链接密码啥的 默认没有设置

  • CLIENTS 用户连接数

    maxclients 10000 默认10000

  • MEMORY MANAGEMENT 内存管理

  • LAZY FREEING 文件释放配置

  • KERNEL transparent hugepage CONTROL 内核控件

  • APPEND ONLY MODE 附加模块

    。。。。。。

  • LUA SCRIPTING 反入侵脚本

    有点高级!不了解

  • SLOW LOG 慢日志

    应该是一些关于日志的配置

  • EVENT NOTIFICATION 事件通知

    没看懂

  • ADVANCED CONFIG 高级配置

    可配置数据类型的最大拆分值

​ 不如hash在ziplist和hashtable中切换的条件

第五部分 Redis集群模式

redis集群模式一共有三种

  • 主从复制(集群基础)
  • 哨兵模式
  • 集群

作用就是读写分离,提高服务器性能,增加缓存容错

1. 主从复制

最简单的集群模式,这是redis集群的基础

实现方式就是使用数据同步技术,同步主从之间的数据

redis采用乐观复制策略,允许短时间内主-从数据内容不同,当然最后还是相同的。

特点

  • 读写分离(优点)
  • 从机不能写(缺点)
  • 主机宕机,集群不能写(缺点)

实现步骤

  • 修改主机配置文件
  • 修改从机配置文件
  • 测试
① 修改主机配置文件

复制一份配置文件

修改:
  :69    bind 192.168.170.31     绑定访问IP,就是本机ip          
  :92    port 6379               例端口号          
  :136   daemonize yes           守护方式运行
② 修改从机配置文件

复制配置文件

修改:
  :69    bind 192.168.170.32     绑定IP          
  :92    port 6379               实例端口号          
  :136   daemonize yes            守护方式运行          
  :G     slaveof   192.168.170.31 6666    主机ip以及端口,指定自己是谁的从机
③ 测试

启动测试

/usr/redis/bin/redis-server  /usr/redis/bin/master.conf    // 主机启动
/usr/redis/bin/redis-server  /usr/redis/bin/slave1.conf	   // 从机启动

可以使用info来查看,集群状态
④ 原理

在这里插入图片描述

2. 哨兵模式

哨兵模式是主从复制的升级版,用来解决主从复制的痛点

概念

哨兵对Redis集群进行监控,当主机宕机后,根据一些配置将从机却换为主机,保证集群正常运行

特点

  • 防止单点故障(优点)
  • 读写分离(优点/缺点)
  • 主机宕机后,会自动补救(优点)
  • 宕机时(系统不能写)

实现

  • 修改Redis哨兵配置文件
  • 以哨兵模式启动服务
① 哨兵模式实现

修改配置文件

sentinel.conf

修改:
	:17  protected-mode no 关闭本机保护
	:21  port 26379        哨兵服务端口,一般不改
	:26  daemonize yes     后台运行
	:36  logfile "./temp.log" 日志文件位置
	:84  sentinel monitor mymaster 192.168.170.31 6666  2   要监视的主机ip、端口以及集群哨兵总数/2
	:103 sentinel auth-pass mymaster 123456    校验密码
	:113 sentinel down-after-milliseconds mymaster 30000     主机宕机最长时长,一般不改
② 启动
./redis-sentinel sentinel.conf
③ 原理

在这里插入图片描述

3. 集群

将多台redis相互连接,并按一定规则将其分为主从关系,数据互通。

特点

  • 高可用,防止单点故障,去中心化
  • 高性能,集群后,集群中每个一节点和单机版能力同级的(可读可写)
  • 扩展方便,按需动态增加或者减少集群中节点的数量
  • 解决master写压力,每个master都可以读写

实现

  • 修改配置文件
  • 启动所有节点
  • 使用集群命令连接节点
  • 连接集群
① 修改配置文件

每一个节点的配置文件都要修改,以一份为例

:69  bind 本机ip
:92  port 端口
:136 daemonize yes 后端运行
:158 pidfile /var/run/redis_端口.pid  进程id
:699 appendonly yes aop  日志开启
:832 cluster-enabled yes 开启集群(重要)
:cluster-config-file  nodes_端口.conf  集群配置文件
:cluster-node-timeout 15000   节点连接超时时长,超过此时长表示宕机
② 启动节点
./redis-serve redis.conf
...
③ 串联所有节点

只用在第一次串联集群时执行

/usr/redis/bin/redis-cli --cluster create --cluster-replicas 1 192.168.37.100:8001 192.168.37.100:8002 192.168.37.101:8003 192.168.37.101:8004 192.168.37.102:8005 192.168.37.102:8006
④ 连接集群

一定要携带 -c 不然不是集群状态

/usr/redis/bin/redis-cli -c -h 192.168.37.100 -p 8001    

获取集群中所有的key

⑤ 集群常用命令
  • redis-cli --cluster create --cluster-replicas 1 ip… 设置集群
  • cluster nodes 获取节点详情
  • cluster meet 将指定redis服务 添加到集群
  • cluster forget <node_id> 将指定节点移除集群

第六部分 Redis消息订阅

在这里插入图片描述

1. 订阅
① subscribe channel1 channel2…

订阅频道,一次性可以订阅多个

127.0.0.1:6379> subscribe channel1 channel2  //订阅多个频道
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel1"
3) (integer) 1
1) "subscribe"
2) "channel2"
3) (integer) 2
② psubscribe channel1 channel2

订阅频道,支持通配符

③ unsubscribe channel1 …

取消订阅,不指定频道视为全部取消

④ punsubscribe channel1 …

取消订阅,支持通配符

2. 发布

2.publish channel message

127.0.0.1:6379> publish channel1 hello 
(integer) 1

第七部分 Redis事务

1. 特点

事务就是串一些命令,防止他人插队

  • redis的事务是一个单独的隔离的空间
  • redis事务没有隔离级别
  • redis事务没有原子性,也就是有命令执行错误,不会发生回滚
  • redis使用乐观锁

事务中的命令会序列化,然后按顺序执行

事务分三步 1.组队命令 2.编译命令 3.执行命令

在这里插入图片描述

2. 事务操作
① multi

开启事务

开启事务之后可以开始添加命令

127.0.0.1:6379> multi   //开启事务
OK
127.0.0.1:6379(TX)> set k1 llz
QUEUED							//命令添加成功
127.0.0.1:6379(TX)> set k2 mmm
QUEUED
127.0.0.1:6379(TX)> 
② exec

编译命令

之后立刻执行

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 llz
QUEUED
127.0.0.1:6379(TX)> set k2 mmm
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) OK
③ discard

中断命令组队

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k5 va
QUEUED
127.0.0.1:6379(TX)> set k6 ga
QUEUED
127.0.0.1:6379(TX)> discard		//中断
OK
127.0.0.1:6379> 
④ watch

监视属性,就相当于给key上锁

当他发生改变时,执行他的命令会失败

用户1

127.0.0.1:6379> watch k1  	//监视k1
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> incrby k1 100  //改变k1
QUEUED

127.0.0.1:6379(TX)> exec  //执行操作 k1增加
1) (integer) 200
127.0.0.1:6379> 
用户2
127.0.0.1:6379> watch k1	//监视k1
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> incrby k1 100
QUEUED	
127.0.0.1:6379(TX)> exec		//因为k1已经改变所以执行错误
(nil)
127.0.0.1:6379> 

⑤ 错误提醒
  • 在multi阶段出现代码错误,则整个事务代码作废
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2			//错误代码
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379(TX)> exec			//强制之行全错
(error) EXECABORT Transaction discarded because of previous errors.
  • 在exec阶段存在错误代码,则之影响一行代码
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> incr k1		//k1自增  明显不能自增,但是加入成功
QUEUED
127.0.0.1:6379(TX)> exec			
1) OK							//第一行执行成功
2) (error) ERR value is not an integer or out of range  //执行失败

3. 事务锁
① 悲观锁

悲观锁就是操作一次加个锁,操作结束在把锁去掉

效率低

在这里插入图片描述

② 乐观锁

乐观锁就是加版本号,执行命令前先检查一下版本号是否匹配

非常适合多读的数据

在这里插入图片描述

第八部分 Redis持久化

1. RDB

rdb 写时拷贝技术

流程如下:

在这里插入图片描述

rdb持久化不会直接将内容写入dump文件

而是开一个子进程,子进程会写一个临时文件,完成之后在同步到dump文件

优点

  • 适合大规模数据恢复
  • 节省磁盘空间
  • 数据恢复速度快

缺点

  • 因为要写临时文件,所以会占用双倍空间
  • rdb最后一次更新的数据可能会丢失

配置文件

SNAPSHOTTING

​ 1.stop-writes-on-bgsave-error yes 当磁盘无法写入时是否停止redis写操作

​ 2.dbfilename dump.rdb 默认持久化文件名字

​ 3.dir ./ 持久化存储的路径 ./ 代表当前路径,也就是启动目录

​ 4.rdbcompression yes 持久化文件是否需要压缩,redis使用L2F算法

​ 5.rdbchecksum yes 持久化完整性检查;持久化前redis会使用CRC64算法进行校验,会有10%的性能消耗

​ 6.save 保存频率,手动进行(一般不用);save 300 100 300s检测一下如果有100个key变化那就持久化

2. AOF

aof 会以追加的形式将指令集添加到appendonly.aof文件

当appendonly.aof文件过大时redis会启动重写

会将文件指令进行压缩

例如:

set k1 v1

set k2 v2

=> set k1 v1 k2 v2 //指令集

重写阈值由自己设置

注:重写触发时,redis会创建一个子进程完成该工作,类似rdb过程

appenonly.aof文件修复

如果appendonly.aof文件不小心损坏可以修复(断电,磁盘满了)

使用

redis-check-aof --fix appendonly.aof

并且redis会给出比较结果

配置文件

APPEND ONLY MODE

​ 1.appendonly no 是否开启aof持久化模式

​ 2.appendfilename “appendonly.aof” 持久化文件名

​ 3.appendfsync always/everysecno 同步日志的频率 时刻同步/每秒同步/让操作系统决定同步(跟自己的情况而定)

​ 4.no-appendfsync-on-rewrite no 重写时是否要使用 appendfsync

​ 5.auto-aof-rewrite-percentage 100 设置重写时文件大小 阈值

​ 6.auto-aof-rewrite-min-size 64mb 设置重写最小文件的大小

3. 持久化总结
  • 推荐两种一起用,两个都开启默认使用appendonly
  • 对数据不敏感,推荐RDB
  • 不建议单独用AOF,有bug
  • 只做缓存都不用

第十部分 Redis 失效问题

1. 缓存穿透

什么是缓存穿透?

​ 缓存穿透是指,缓存失去意义,甚至不如不加

**场景:**大量请求访问一个redis不存在,数据库也不存在的key

例如:

  • 不停查询一个不存在的数据,redis缓存未命中,也不能缓存数据,导致一直访问持久层,缓存失去意义

解决办法

  • 缓存空对象 key null ,会占用很多空间,一般会设置过期值
  • 运用bitmap布隆缓存拦截器,将存在的key保存到bitmap中。访问时先判断key是否存在,存在再放过去
2. 缓存击穿

什么是缓存击穿?

​ 某一key失效的瞬间,后端启用大量线程来补救,导致后端负载过大,甚至导致服务器崩坏

**场景:**大量请求访问一个缓存不存在,数据库存在的key

例如:

  • 双11购物,瞬间高并发一个没有缓存的key,会导致后端启用多线程重建缓存

  • 或者就是重建缓存

解决办法

  • 加锁,单线程重构,其他线程等待(set n/x)
  • 延长热点key的过期时间,甚至是不过期,属于是物理解决,具体情况比价复杂

3. 缓存雪崩

什么是缓存雪崩?

​ 缓存层因为某些情况挂掉,或者大量key在短时间内过期,导致持久层压力剧增进而导致系统崩溃成为雪崩

**场景:**大量key同时失效

解决办法

  • 设置多层缓存。比如nignx缓存,redis缓存,等
  • 多节点缓存
  • key的过期时间随机

第十一部分 Redis+springboot

1. 整合一(只操作String)

这个整合比较简单,不能缓存对象、不能使用注解缓存

步骤

  • 导入依赖
  • 配置yml文件
  • 编写测试类
① 导入依赖
<!--    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>
        </dependency>
② 配置yml文件
spring:
  redis:
    host: 192.168.37.100
    port: 6379
    #    使用的数据库
    database: 0
    #    链接超时时间
    #    connect-timeout:
    lettuce:
      pool:
        #        最大连接数
        max-active: 20
        #        最大等待时间 负数为永久
        max-wait: -1
        #        最大空闲连接数
        max-idle: 5
        #        最小空闲连接数
        min-idle: 0
#第二种redis连接方法

spring:
   redis:
     username: root
     url: redis://@192.168.37.100:6379
③ 编写测试类

使用Spring提供的工具类StringRedisTemplate

	@Autowired
	private StringRedisTemplate redisTemplate;

    @Test
    @Rollback(false)    // 防止测试数据回滚 配个Transactional使用
    @Transactional
    void stringTest() {
        ValueOperations<String, String> opsForString = redisTemplate.opsForValue();	
        
    }
        
2. 整合二(缓存对象)

思路:

  1. 导入依赖
  2. 配置yml
  3. 配置自定义的RedisTemplate,CacheManager
  4. 编写demo 测试
① 导入依赖
 		//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>
        </dependency>
		//json格式依赖
		<dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.12.5</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.12.5</version>
        </dependency>
② 配置
  • 配置application.yml
spring:
  redis:
    host: localhost
    port: 6379
#    使用的数据库
    database: 0
#    链接超时时间
#    connect-timeout:
    lettuce:
      pool:
#        最大连接数
        max-active: 20
#        最大等待时间 负数为永久
        max-wait: -1
#        最大空闲连接数
        max-idle: 5
#        最小空闲连接数
        min-idle: 0
③ 配置文件
package com.example.redisspring2;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;

/**
 * reids配置类
 */

@Configuration
// 开启redis缓存
@EnableCaching   
public class redisConfig extends CachingConfigurerSupport {

    // 所有进行redis存储的对象以及字符串都要序列化。所以在这里我们自定义序列化规则,使得我们自定义的其他实体类不用去实现序列化接口
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);

        // 使用Jackson2JsonRedisSerialize 替换默认序列化
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

        // 设置value的序列化规则和 key的序列化规则
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();

        return redisTemplate;
    }

	// 缓存管理器对我们缓存的数据进行一些设置,在使用注解缓存时,可以让spring帮我们实现一些缓存步骤    
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

        //解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);

        // 配置序列化(解决乱码的问题),过期时间30秒
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(1800000))
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
                .disableCachingNullValues();

        RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .build();
        return cacheManager;
    }
}

④ 使用StringRedisTemplate

注入使用RedisTemplate或StringRedisTemplate对象(第一个专门操作String)

一般情况下只操作StringRedisTemplate就行了

@Autowired
    StringRedisTemplate stringRedisTemplate;

    void example(){
        //操作String类型 K-V
        ValueOperations valueOperations = stringRedisTemplate.opsForValue();
        
        //操作List类型 K-[v1,v2...]        有序列表(放入顺序和存放顺序一致)
        ListOperations listOperations = stringRedisTemplate.opsForList();
        
        //操作Set类型  k-[v1,v2,v3...]     无序列表且元素不重复(放入顺序和存放顺序不一致)
        SetOperations setOperations = stringRedisTemplate.opsForSet();
        
        //操作Hash类型 K-[f1,v1,f2,v2...]  适合对象存储
        HashOperations hashOperations = stringRedisTemplate.opsForHash();
        
        //操作Zset类型 K-[s1,v1,s2,v2...]  和list相似不过内部元素会根据s的值进行排序
        ZSetOperations zSetOperations = stringRedisTemplate.opsForZSet();
        
        //操作HyperLogLog类型 K-[v1,v2,v3...]  元素不重复,主要用于统计数量
        HyperLogLogOperations hyperLogLogOperations = stringRedisTemplate.opsForHyperLogLog();
        
        //操作Geospatial类型  K-[经度 维度 name...] 存放地理位置
        GeoOperations geoOperations = stringRedisTemplate.opsForGeo();
    }
3. 整合三(注解缓存)

思路:

  1. 导入依赖
  2. 配置yml
  3. 编写RedisConfig
  4. 编写测试demo
  5. 添加CacheManager
  6. 修改测试demo
① 导入依赖
<!-- spring boot redis缓存引入 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- lecttuce 缓存连接池-->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>
② 配置yml
spring:
  redis:
    host: 192.168.37.128
    port: 6379
    database: 0
    #password: 123456 #默认为空
    lettuce:
      pool:
        max-active: 20  #最大连接数,负值表示没有限制,默认8
        max-wait: -1    #最大阻塞等待时间,负值表示没限制,默认-1
        max-idle: 8     #最大空闲连接,默认8
        min-idle: 0     #最小空闲连接,默认0
③ 编写RedisConfig
/**
 * 我们自定义一个 RedisTemplate,设置序列化器,这样我们可以很方便的操作实例对象。
 * 否则redis自动使用对象的jdk序列化
 */
@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Serializable> redisTemplate(LettuceConnectionFactory connectionFactory) {
        RedisTemplate<String, Serializable> redisTemplate = new RedisTemplate<>();
        redisTemplate.setKeySerializer(new StringRedisSerializer());//key序列化方式
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());//value序列化
        redisTemplate.setConnectionFactory(connectionFactory);

        return redisTemplate;
    }
}
④ 编写测试demo
public R getById(@PathVariable String id) {
    Gson gson = new Gson();
    // 当我们处理一个请求时 先去redis中获取一下请求数据是否存在
    Serializable object = redisTemplate.opsForValue().get("ky1");
    Ad ad = null;
    // 没有的话就去数据库里找
    if (ObjectUtil.isNull(object)){
        ad = adService.getById(id);
        // 将数据存入缓存
        redisTemplate.opsForValue().set("ky1",gson.toJson(ad));
    }
    return R.ok().data("item", object);
}
⑤ 添加CacheManager

在第④步中。我们获取一个数据 先去缓存找,没有的话再去数据库,最后将数据存到缓存中。 这一步每一个需要缓存的数据请求几乎都要写,所以我们可以借助Spring切面编程

  1. Spring给我们提供了 面向切面请求缓存的接口,即CacheManager
  2. Redis实现了Spring提供的接口
  3. 我们要做的就是把Redis实现的类加入到Spring容器中

在RedisConfig中添加,在这里我们也可以进行一些其他统一设置

@Bean
public CacheManager cacheManager(LettuceConnectionFactory connectionFactory) {

    RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
            //过期时间600秒
            .entryTtl(Duration.ofSeconds(600))
            // 配置序列化
            .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
            .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
            .disableCachingNullValues();

    RedisCacheManager cacheManager = RedisCacheManager.builder(connectionFactory)
            .cacheDefaults(config)
            .build();
    return cacheManager;
}

另外还要为RedisConfig 添加注解 @EnableCaching,接下来就可以使用Spring提供的注解了

⑥ 修改测试demo
@Cacheable(value = "AdInfo")
public R getById(@PathVariable String id) {
    Ad ad = adService.getById(id);
    return R.ok().data("item", ad);
}

从以上代码我们可以看出,代码非常少,只有自己的核心业务代码,但是缓存的功能并没有少

@Cacheable(value = “AdInfo”)的意思:

  1. Cacheable表示 先去缓存找,没有的话再去数据库,最后将数据存到缓存中
  2. 属性value 表示 将数据存入Redis时 Key为 value值::参数值

例如:

“AdInfo::1194556896025845762”

“AdInfo::1194607458461216769”

非常灵活

4. StringRedisTemplate

StringRedisTemplate是Spring提供操作String的工具类

获取 各种数据类型存储String 工具类

//操作String类型 K-V
ValueOperations valueOperations = stringRedisTemplate.opsForValue();

//操作List类型 K-[v1,v2...]        有序列表(放入顺序和存放顺序一致)
ListOperations listOperations = stringRedisTemplate.opsForList();

//操作Set类型  k-[v1,v2,v3...]     无序列表且元素不重复(放入顺序和存放顺序不一致)
SetOperations setOperations = stringRedisTemplate.opsForSet();

//操作Hash类型 K-[f1,v1,f2,v2...]  适合对象存储
HashOperations hashOperations = stringRedisTemplate.opsForHash();

//操作Zset类型 K-[s1,v1,s2,v2...]  和list相似不过内部元素会根据s的值进行排序
ZSetOperations zSetOperations = stringRedisTemplate.opsForZSet();

//操作HyperLogLog类型 K-[v1,v2,v3...]  元素不重复,主要用于统计数量
HyperLogLogOperations hyperLogLogOperations = stringRedisTemplate.opsForHyperLogLog();

//操作Geospatial类型  K-[经度 维度 name...] 存放地理位置
GeoOperations geoOperations = stringRedisTemplate.opsForGeo();

// 操作Key  ,所有的Operations都可以获取RedisOperations  可以使用操作key的命令
RedisOperations<String, String> operations = opsForString.getOperations();
① ValueOperations

redis的String类型存储String

ValueOperations<String, String> opsForString = redisTemplate.opsForValue();
    // 获取指定key
    opsForString.get("className");
    // 设置一个key
    opsForString.set("llz","llzaaa");
    // 如果key存在则会修改值
    opsForString.setIfPresent("desk1", "123");
    // 如果key不存在则会创建成功
    opsForString.setIfAbsent("desk1", "111");
    // 批量添加字符串
    Map<String,String> map = new HashMap<>();
    map.put("aaa","111");
    map.put("bbb","222");
    map.put("ccc","333");
    opsForString.multiSet(map);
    // 批量获取value 不存在为null
    List<String> list = new ArrayList<>();
    list.add("aaa");
    list.add("bbb");
    list.add("nnn");
    opsForString.multiGet(list);
    // 自减 如果key不存在,则初始化为0,再-1
    opsForString.decrement("aaa");
    opsForString.decrement("aaa", 100L);
    // 自增 如果key不存在,则初始化为0,再+1
    opsForString.increment("eee");
    opsForString.increment("ddd", 100L);
    // 获取key的长度 不存在则值为0
    opsForString.size("aaa");
    opsForString.size("bbb");
    opsForString.size("nnn");
    // 在指定key后追加value
    opsForString.append("aaa", "100");
② ListOperations
ListOperations<String, String> listOperations = redisTemplate.opsForList();
	// 在列表右侧放入数据,返回列表元素个数
    opsForList.rightPush("strList","aaa");
    // 在列表左侧放入数据,返回列表元素个数
    opsForList.leftPush("strList", "ccc");
    // 一次存入多个元素
    opsForList.leftPushAll("strList",ArrayList<>())
    // 从左侧开始,获取指定角标的元素
    opsForList.index("strList", 2);
    // 从左侧开始,获取指定范围内的所有值(0 -1,为所有元素)
    opsForList.range("strList",0,-1);
    // 返回列表的长度
    opsForList.size("strList");
    // 对列表进行截取, -1 为最后一个元素,-2为倒数第二个元素
    opsForList.trim("strList",1,-1);
    // 移除并返回左侧第一个元素
    opsForList.leftPop("strList");
    // 设置指定索引位置的值
    opsForList.set("strList",0,"一般玩");
③ Set
SetOperations<String, String> setOperations = redisTemplate.opsForSet();
    // 添加元素,重复元素无法添加,返回添加成功的个数
    setOperations.add("setList2", "aaa","111","222");
    // 获取集合中所有的value
    setOperations.members("setList");
    // 判断指定元素是否在集合之中
    setOperations.isMember("setList", "aaa");
    // 返回集合并集
    setOperations.union("setList", "setList2");
    // 返回集合交集
    setOperations.intersect("setList", "setList2");
    // 返回集合一相较于集合二的差集
    setOperations.difference("setList2", "setList");
    // 移除一个或多个元素返回移除个数
    setOperations.remove("setList", "aaa", "bbb");
    // 随机获取并移除一个元素
    setOperations.pop("setList");
④ Hash
HashOperations<String, Object, Object> hashOperations = redisTemplate.opsForHash();
    // 放入/覆盖单个 k-v
    hashOperations.put("strMap","key2","aaa");
    // 通过k获取v
    hashOperations.get("strMap", "key1");
    // 批量放入v-k
    hashOperations.put("strMap",Map);
    // 批量获取v
    hashOperations.multiGet("strMap",List)
    // 是否存在指定k
    hashOperations.hasKey("strMap", "key1");
    // 返回map的长度
    hashOperations.size("strMap");
    // 删除一个或多个k  返回删除成功的个数
    hashOperations.delete("strMap", "key1", "ccc");
    // 获取所有的k
    hashOperations.keys("strMap");
    // 获取所有的v
    hashOperations.values("strMap");
⑤ zSetOperations
ZSetOperations<String, String> zSetOperations = redisTemplate.opsForZSet();
    // 添加一个值,并指定他的分数值,集合按照分数值进行排序(如果分数值存在,则会放在其后)
    zSetOperations.add("zSet", "zzzz", 10);
    // 获取指定范围内的值,(0,-1为全部)
    zSetOperations.range("zSet", 0, -1);
    // 获取指定分数范围内的元素值
    zSetOperations.rangeByScore("zSet", 2, 10);
    // 倒叙获取指定角标区间内的元素(先倒叙,再按区间找元素)
    zSetOperations.reverseRange("zSet", 0, 2);
    // 倒叙获取指定分数区间内的元素
    zSetOperations.reverseRangeByScore("zSet", 2, 10);
    // 移除一个或多个指定元素,返回移除个数
    zSetOperations.remove("zSet","zzzz");
    // 移除指定角标范围内的元素
    zSetOperations.removeRange("zSet",0,-1);
    // 移除指定分数范围内的元素
    zSetOperations.removeRangeByScore("zSet",0,100);
    // 获取指定分数范围内元素的个数,闭区间
    zSetOperations.count("zSet", 2, 10);
    // 获取一个或多个元素的分数值
    zSetOperations.score("zSet","zzz","a");
    // 获取指定角标范围内的元素值与分数
    zSetOperations.rangeWithScores("zSet", 0, 3);
    // 获取集合长度
    zSetOperations.zCard("zSet");
    zSetOperations.size("zSet");
⑧ RedisOperations

用来执行redis中key的相关命令,比如:获取所有key,为key添加过期时间等等

可用通过以上7个类的 getPoerations() 获取对象

// 获取redisOperations 可以使用keys相关命令  以String为例
RedisOperations<String, String> operations = opsForString.getOperations();
    // 获取所有key
    operations.keys("*").forEach(System.out::println);
    // 删除key
    operations.delete("llz");
    // 修改key名称
    operations.rename("className","deskMate");
    // 为key设置过期时间
    operations.expire("deskMate",-1L,TimeUnit.SECONDS);
    // 获取过期时间
    operations.getExpire("desk2");
4. 连接redis集群
  • 确保redis集群启动
  • 配置yml
spring:
  redis:
    lettuce:
      pool:
        #        最大连接数
        max-active: 20
        #        最大等待时间 负数为永久
        max-wait: -1
        #        最大空闲连接数
        max-idle: 5
        #        最小空闲连接数
        min-idle: 0
    cluster:
      nodes:
        - 192.168.37.100:8001
        - 192.168.37.100:8002
        - 192.168.37.101:8003
        - 192.168.37.101:8004
        - 192.168.37.102:8005
        - 192.168.37.102:8006
      max-redirects: 3

其他语法使用不变

第十二部分 Redis+Mybatis-Plus缓存

开启mybatis缓存,以redis集群为数据存储处。

1. Mapper层缓存

也就是对Mapper中SQL语句查出的结果进行缓存,并不是对Service层的结果进行缓存

实现步骤

  • 导入依赖
  • 配置yml
  • 编写MyBatis缓存配置文件
  • 编写Redis配置文件
  • 在需要缓存的Mapper.xml文件中开启缓存
  • 测试
① 导入依赖
<!--        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>
</dependency>
<!--        json格式依赖-->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.12.5</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.12.5</version>
</dependency>
② 配置yml
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    #如果驱动版本为8.0选择带‘cj’的名称 5.0不用
    driver-class-name: com.mysql.cj.jdbc.Driver
    #mysql是8.0版本需要带时区serverTimezone=GMT%2B8
    url: jdbc:mysql://localhost:3306/test_local2?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
    username: root
    password: root
    # redis集群配置
  redis:
    lettuce:
      pool:
        #        最大连接数
        max-active: 20
        #        最大等待时间 负数为永久
        max-wait: -1
        #        最大空闲连接数
        max-idle: 5
        #        最小空闲连接数
        min-idle: 0
    cluster:
      nodes:
        - 192.168.37.100:8001
        - 192.168.37.100:8002
        - 192.168.37.101:8003
        - 192.168.37.101:8004
        - 192.168.37.102:8005
        - 192.168.37.102:8006
      max-redirects: 3

#mybatis-plus配置
mybatis-plus:
  configuration:
    #日志配置,控制台可以输出sql语句
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case: true
  #mapper.xml映射文件路径 这是默认路径,可以不写
  mapper-locations: classpath*:/mapper/**/*.xml
③ 编写MyBatis缓存配置文件

注意实现的 Cache 接口为Mybatis的,别写错了

import cn.hutool.core.util.StrUtil;
import org.apache.ibatis.cache.Cache;
import org.springframework.data.redis.core.ValueOperations;

public class MybatisRedisCacheConfig implements Cache {

    private String id;

    // 对象不交给Spring管理,需要使用静态方法注入
    private static ValueOperations<String, Object> valueOperations;

    public static void setValueOperations(ValueOperations<String, Object> valueOperationsParam) {
        valueOperations = valueOperationsParam;
    }

    public MybatisRedisCacheConfig(String id) {
        if (StrUtil.isBlank(id)) {
            throw new IllegalArgumentException("id不能为空");
        }
        this.id = id;
    }

    @Override
    public String getId() {
        return id;
    }

    @Override
    public void putObject(Object o, Object o1) {
        valueOperations.set(o.toString(), o1);
    }

    @Override
    public Object getObject(Object o) {
        return valueOperations.get(o.toString());
    }

    @Override
    public Object removeObject(Object o) {
        return valueOperations.getOperations().delete(o.toString());
    }

    @Override
    public void clear() {

    }

    @Override
    public int getSize() {
        return 0;
    }
}
④ 编写Redis配置文件
package com.example.security01.config.redis;

import com.example.security01.config.MybatisRedisCacheConfig;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);

        // 使用Jackson2JsonRedisSerialize 替换默认序列化
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

        // 设置value的序列化规则和 key的序列化规则
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();

        // 因为Myabtis的缓存配置文件不交给Spring管理,所以需要在这里手动复制
        MybatisRedisCacheConfig.setValueOperations(redisTemplate.opsForValue());
        return redisTemplate;
    }
}
⑤ 在需要缓存的Mapper.xml文件中开启缓存

在需要缓存的Mapper文件中添加一下代码

<cache type="com.example.security01.config.MybatisRedisCacheConfig"/>

注意:MybatisPlus自带的方法不能缓存,必须是Mapper手写的查询语句

⑥ 测试
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
尚硅谷是一个教育机构,他们提供了一份关于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 ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值