Redis入门笔记

基础

redis所有的储存格式为key-value形式
单个命令为原子性

keys * 获取所有符合正则表达式的keys
flushDb 清空当前数据库
flushAll 清空所有数据库
move key 9 运动key到9号数据库, 从0号开始算
exist key 当前key是否存在
exprie key 10 设置当前key过期时间
ttl key 查看key过期时间,-1永久存在,-2不存在
select 3 切换到3号数据库

String字符串

储存形式为key-value,value为一个字符串

设置和获取string值或者长度

#############################################################################
127.0.0.1:6379> set k1 va1 #设置值
OK
127.0.0.1:6379> get k1     #获取值
"va1"
127.0.0.1:6379> keys *     #获取所有key,数据量大时警惕使用
1) "k1"
127.0.0.1:6379> exists k1  #查看key是否存在
(integer) 1
127.0.0.1:6379> append k1 23    #在指定key的value后面添加字符串
(integer) 5
127.0.0.1:6379> get k1        
"va123"
127.0.0.1:6379> strlen k1    #获取指定key的value长度
(integer) 5
#############################################################################

整数自增自减,加减

#
#value为整数时可以执行
#i++ 数字自增自减
#步长 i+= i-=
127.0.0.1:6379> set k1 0
OK
127.0.0.1:6379> get k1
"0"
127.0.0.1:6379> incr k1 #k1自增1
(integer) 1    #返回结果
127.0.0.1:6379> decr k1    #k1自减1
(integer) 0
127.0.0.1:6379> incrby k1 10 #k1加上指定值
(integer) 10
127.0.0.1:6379> decrby k1 100 #k1减去指定值
(integer) -90
#############################################################################

字符串范围操作 range相关

#
#字符串范围操作 range相关
#
127.0.0.1:6379> set k1 "h1llo world"
OK
127.0.0.1:6379> get k1
"h1llo world"
127.0.0.1:6379> getRange k1 0 4    #获取指定范围的字符串
"h1llo"                            #双向索引
127.0.0.1:6379> getRange k1 0 6    #正向为 0,len-1
"h1llo w"                            #负向为 -1,-len
127.0.0.1:6379> getRange k1 0 -1
"h1llo world"
127.0.0.1:6379> getRange k1 -1 -3
""
127.0.0.1:6379> getRange k1 -3 -1
"rld"

#范围替换
127.0.0.1:6379> set k2 abcdef
OK
127.0.0.1:6379> get k2
"abcdef"
127.0.0.1:6379> setRange k2 3 xxxx    #从指定范围开始替换字符串
(integer) 7                            
127.0.0.1:6379> get k2
"abcxxxx"

设置字符串过期时间或者不存在设置

#setex (set with exprie) #设置字符串并设置过期时间
#setnx (set if not exist) #当key不存在时设置字符串(分布式锁中会常用)
127.0.0.1:6379> setex k1 20 1ewdfaf #设置k1值为1ewdfaf,20秒后过期
OK
127.0.0.1:6379> ttl k1  #查看key过期时间,正数为剩余时间,-1为永久存在,-2为key不存在
(integer) 16
127.0.0.1:6379> ttl k1
(integer) 7
127.0.0.1:6379> get k1
"1ewdfaf"
127.0.0.1:6379> get k1
(nil)
127.0.0.1:6379> ttl k1
(integer) -2


127.0.0.1:6379> setnx k1 wqeue #当k1不存在时设置值为wqeue
(integer) 1          #成功返回1.失败返回0
127.0.0.1:6379> get k1
"wqeue"
127.0.0.1:6379> setnx k1 wqeue
(integer) 0

批量设置和获取

127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3    #批量设置
OK
127.0.0.1:6379> mget k1 k2 k3        #批量获取
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> msetnx k1 v1 k6 v6     #当所有key不存在时设置值
(integer) 0
127.0.0.1:6379> get k6
(nil)

getset

127.0.0.1:6379> getset key v1  #先get后set
(nil)
127.0.0.1:6379> getset key value
"v1"

LIst列表

大部分与list相关的命令都是以l开头

设置或者获取列表值

127.0.0.1:6379> lPush list1 one two three    #将一个或者多个值插入列表头部
(integer) 3
127.0.0.1:6379> lPush list1 four 
(integer) 4
127.0.0.1:6379> lRange list1 0 -1    #获取索引范围内的列表元素,支持双向索引
1) "four"
2) "three"
3) "two"
4) "one"
127.0.0.1:6379> lRange list1 0 1    
1) "four"
2) "three"
127.0.0.1:6379> rPush list1 five    #将一个或者多个值插入列表尾部
(integer) 5
127.0.0.1:6379> lRange list1 0 -1
1) "four"
2) "three"
3) "two"
4) "one"
5) "five"

抛出列表元素

127.0.0.1:6379> lRange list1 0 -1 
1) "four"
2) "three"
3) "two"
4) "one"
5) "five"
127.0.0.1:6379> lPop list1 2    #从列表头部抛出指定数量选数,默认为1
1) "four"
2) "three"
127.0.0.1:6379> rPop list1 2    #从列表尾部抛出指定数量选数,默认为1
1) "five"
2) "one"
127.0.0.1:6379> lRange list1 0 -1
1) "two"

下标访问和获取列表长度

127.0.0.1:6379> lRange list1 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
6) "two"
127.0.0.1:6379> lIndex list1 2 #根据下标获取列表元素
"3"
127.0.0.1:6379> lIndex list1 0
"5"
############################################################
127.0.0.1:6379> lRange list1 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
6) "two"
127.0.0.1:6379> lLen list1    #获取列表长度
(integer) 6
127.0.0.1:6379> 

删除列表元素

127.0.0.1:6379> lRange list1 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
6) "two"
127.0.0.1:6379> lRem list1 1 two #删除一个或者多个列表元素,返回成功删除个数
(integer) 1
127.0.0.1:6379> lRange list1 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
127.0.0.1:6379> lRem list1 2 1
(integer) 1
127.0.0.1:6379> lRange list1 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
127.0.0.1:6379> lPush list1 2 2 2 2 2
(integer) 9
127.0.0.1:6379> lRange list1 0 -1
1) "2"
2) "2"
3) "2"
4) "2"
5) "2"
6) "5"
7) "4"
8) "3"
9) "2"
127.0.0.1:6379> lRem list1 3 2
(integer) 3

list截断和移动元素到新list

127.0.0.1:6379> Lrange list1 0 -1
1) "hello world"
2) "hello world1"
3) "hello world2"
4) "hello world3"
5) "hello world4"
6) "hello world5"
7) "hello world6"
8) "hello world7"
127.0.0.1:6379> lTrim list1 2 4  #通过索引截取list,执行后就改变了list
OK
127.0.0.1:6379> Lrange list1 0 -1
1) "hello world2"
2) "hello world3"
3) "hello world4"
###############################################################
#
127.0.0.1:6379> Lrange list1 0 -1
1) "hello world2"
2) "hello world3"
3) "hello world4"
127.0.0.1:6379> rpopLpush list1 list2 #移动原列表的最后一个元素到新列表头
"hello world4"
127.0.0.1:6379> Lrange list1 0 -1
1) "hello world2"
2) "hello world3"
127.0.0.1:6379> Lrange list2 0 -1
1) "hello world4"

通过索引更新指定list元素

127.0.0.1:6379> EXISTS list1 #判断列表是否存在
(integer) 0
127.0.0.1:6379> lset list1 0 one #不存在执行更新会报错
(error) ERR no such key
127.0.0.1:6379> lPush list1 1 2 3 4 5 6 7 8 9
(integer) 9
127.0.0.1:6379> lRange list1 0 -1
1) "9"
2) "8"
3) "7"
4) "6"
5) "5"
6) "4"
7) "3"
8) "2"
9) "1"
127.0.0.1:6379> lSet list1 0 one #更新指定索引的元素
OK
127.0.0.1:6379> lRange list1 0 -1
1) "one"
2) "8"
3) "7"
4) "6"
5) "5"
6) "4"
7) "3"
8) "2"
9) "1"
127.0.0.1:6379> lSet list1 17 one 索引不存在报错
(error) ERR index out of range

插入元素

LINSERT key BEFORE|AFTER pivot value
在找到的第一个参考值(pivot)后面或者前面插入value
127.0.0.1:6379> lRange list1 0 -1
 1) "one"
 2) "8"
 3) "7"
 4) "6"
 5) "5"
 6) "4"
 7) "3"
 8) "2"
 9) "one"
10) "1"
11) "1"
127.0.0.1:6379> lInsert list1 before 1 one #在参考值前插入
(integer) 12
127.0.0.1:6379> lRange list1 0 -1
 1) "one"
 2) "8"
 3) "7"
 4) "6"
 5) "5"
 6) "4"
 7) "3"
 8) "2"
 9) "one"
10) "one"
11) "1"
12) "1"
127.0.0.1:6379> lInsert list1 after 1 one #在参考值后插入
(integer) 13
127.0.0.1:6379> lRange list1 0 -1
 1) "one"
 2) "8"
 3) "7"
 4) "6"
 5) "5"
 6) "4"
 7) "3"
 8) "2"
 9) "one"
10) "one"
11) "1"
12) "one"
13) "1"

Set无序集合

设置和获取set,判断值是否存在与集合

127.0.0.1:6379> sadd myset one #在set中添加元素,可以添加多个值
(integer) 1
127.0.0.1:6379> sadd myset two three four five
(integer) 4
127.0.0.1:6379> sMembers myset #获取set中的所有元素
1) "four"
2) "three"
3) "two"
4) "one"
5) "five"
127.0.0.1:6379> sIsMember myset one #判断set中是否有指定元素,有返回1,没有返回0
(integer) 1
127.0.0.1:6379> sIsMember myset on
(integer) 0

获取set的元素个数和移除指定元素

127.0.0.1:6379> scard myset #获取set的元素个数
(integer) 5
##########################################################
127.0.0.1:6379> sMembers myset
1) "five"
2) "one"
3) "two"
4) "three"
5) "four"
127.0.0.1:6379> sRem myset one  #移除指定元素
(integer) 1
127.0.0.1:6379> sMembers myset
1) "five"
2) "two"
3) "three"
4) "four"
127.0.0.1:6379> sRem myset one two #移除多个指定元素,返回成功移除个数
(integer) 1
127.0.0.1:6379> sMembers myset
1) "five"
2) "three"
3) "four"

随机抽取set中的元素

127.0.0.1:6379> smembers myset
1) "five"
2) "three"
3) "four"
127.0.0.1:6379> sRandMember myset 2 #随机抽取指定个数的元素,默认为1
1) "four"                      #指定数为整数时为不放回的抽取,最多抽取数为集合元素数
2) "three"                     #指定数为负数时为放回抽取,没有组多抽数
127.0.0.1:6379> sRandMember myset 2
1) "four"
2) "five"
127.0.0.1:6379> sRandMember myset 2
1) "five"
2) "three"
127.0.0.1:6379> sRandMember myset
"three"
127.0.0.1:6379> sRandMember myset
"four"
127.0.0.1:6379> sRandMember myset
"four"127.0.0.1:6379> sRandMember myset -4 #指定数为负
1) "five"
2) "three"
3) "four"
4) "four"
127.0.0.1:6379> sRandMember myset 4 #指定数为正
1) "five"
2) "three"
3) "four"

随机抛出set元素和移动元素到另一个set

127.0.0.1:6379> spop myset 2 #随机抛出指定个数的元素,默认为1
1) "5"
2) "four"
127.0.0.1:6379> smembers myset
1) "three"
2) "34"
3) "6"
4) "7"
5) "8"
6) "five"
###################################################################
127.0.0.1:6379> smembers myset1
(empty array)
127.0.0.1:6379> smembers myset
1) "three"
2) "34"
3) "6"
4) "7"
5) "8"
6) "five"
127.0.0.1:6379> smove myset myset1 five #移动指定值到指定set
(integer) 1
127.0.0.1:6379> smembers myset
1) "three"
2) "34"
3) "6"
4) "7"
5) "8"
127.0.0.1:6379> smembers myset1
1) "five"

set的差、交、并集运算

127.0.0.1:6379> smembers set1
1) "g"
2) "b"
3) "a"
4) "c"
5) "d"
6) "e"
7) "f"
127.0.0.1:6379> smembers set2
1) "g"
2) "j"
3) "i"
4) "e"
5) "f"
6) "h"
7) "k"
127.0.0.1:6379> sDiff set1 set2 #set1对set2的差集运算,可以有多个set2
1) "b"
2) "d"
3) "c"
4) "a"
127.0.0.1:6379> sInter set1 set2 #交集运算,可以有多个set共同运算, 共同好友实现
1) "g"
2) "e"
3) "f"
127.0.0.1:6379> sUnion set1 set2 #并集运算,可以有多个set
 1) "g"
 2) "j"
 3) "a"
 4) "h"
 5) "k"
 6) "b"
 7) "i"
 8) "d"
 9) "e"
10) "c"
11) "f"

Hash map集合

储存形式为key-map

设置、获取、删除hash

127.0.0.1:6379> hSet myhash field1 one field2 two #设置一个或者多个myhash的元素
(integer) 2
127.0.0.1:6379> hget myhash field1 #获取hash中指定key的值
"one"
127.0.0.1:6379> hmget myhash field1 field2 #获取一个或者多个指定key值
1) "one"
2) "two"
127.0.0.1:6379> hgetall myhash #获取指定hash中的所有键值对
1) "field1"
2) "one"
3) "field2"
4) "two"
127.0.0.1:6379> hdel myhash field1 #删除指定hash中的指定key的键值对,key可以有多个
(integer) 1
127.0.0.1:6379> hgetall myhash
1) "field2"
2) "two"

获取hash长度与判断指定键值对是否存在

127.0.0.1:6379> hGetall myhash
1) "field2"
2) "two"
127.0.0.1:6379> hlen myhash #获取hash长度
(integer) 1
#####################################################
127.0.0.1:6379> hexists myhash field2 #判断指定键值对是否存在
(integer) 1
127.0.0.1:6379> hexists myhash field
(integer) 0

获取所有key或者value

127.0.0.1:6379> hgetall myhash
1) "field2"
2) "two"
3) "k1"
4) "v1"
5) "k2"
6) "v2"
7) "k3"
8) "v3"
127.0.0.1:6379> hkeys myhash #获取所有key
1) "field2"
2) "k1"
3) "k2"
4) "k3"
127.0.0.1:6379> hvals myhash #获取所有value
1) "two"
2) "v1"
3) "v2"
4) "v3"

整数键值对加与不存在时设置键值对

127.0.0.1:6379> hget muhash f1
(nil)
127.0.0.1:6379> hget myhash f1
"4"
127.0.0.1:6379> hincrBy myhash f1 1 #指定整数键值对加上指定整数
(integer) 5
127.0.0.1:6379> hincrBy myhash f1 -1
(integer) 4

127.0.0.1:6379> hsetnx myhash f8 3 #当指定key不存在时设置值
(integer) 1
127.0.0.1:6379> hsetnx myhash f8 3
(integer) 0

Zset有序集合

相比于set无序集合增加了用于判断顺序的

添加值与获取值

#设置zset的值,可以设置一个或者多个 先权重,后值
127.0.0.1:6379> zadd myzset 100 xiaoming 500 xiaohong 1000 xioahei
(integer) 3
127.0.0.1:6379> zrange myzset 0 -1 #获取指定索引范围内的值,通过权重从小到大排序
1) "xiaoming"
2) "xiaohong"
3) "xioahei"
127.0.0.1:6379> zrangebyscore myzset -inf +inf #获取指定权重范围内的值,通过权重排序
1) "xiaoming"                                #inf代表无限
2) "xiaohong"
3) "xioahei"
127.0.0.1:6379> zrangebyscore myzset -inf +inf withscores #显示权重
1) "xiaoming"
2) "100"
3) "xiaohong"
4) "500"
5) "xioahei"
6) "1000"
127.0.0.1:6379> zrangebyscore myzset -inf 600 withscores #指定权重最大值为600
1) "xiaoming"
2) "100"
3) "xiaohong"
4) "500"

删除元素与获取元素数量

127.0.0.1:6379> zrange myzset 0 -1
1) "aaa"
2) "xiaoming"
3) "xiaohong"
4) "xioahei"
127.0.0.1:6379> zrem myzset aaa #删除指定的元素
(integer) 1
127.0.0.1:6379> zrange myzset 0 -1
1) "xiaoming"
2) "xiaohong"
3) "xioahei"
127.0.0.1:6379> zcard myzset #获取元素数量
(integer) 3
127.0.0.1:6379> zrange myzset 0 -1 withscores
1) "xiaoming"
2) "100"
3) "xiaohong"
4) "500"
5) "xioahei"
6) "1000"
127.0.0.1:6379> zcount myzset 1 600 #获取指定权重范围内的元素数量
(integer) 2

Geospatial地理位置

这是用于存储和计算经纬度的特殊数据类型
储存格式为 经度 纬度 字符串

添加和获取值

#添加一个经纬度记录,后面的字符串是唯一标识,可以一次添加多个记录
127.0.0.1:6379> geoadd China:city 116.23128 40.22077 beijing
(integer) 1
127.0.0.1:6379> geoadd China:city 116.23128 40.22077 beijing
(integer) 0
127.0.0.1:6379> geoadd China:city 121.48941 31.40527 shanghai 104.10194 30.65984 chengdu 88.31104 43.36378 wulumuqi
(integer) 3
#########################################
127.0.0.1:6379> geoPos China:city beijing #获取指定key的经纬度
1) 1) "116.23128265142440796"
   2) "40.22076905438526495"
127.0.0.1:6379> geoPos China:city shanghai
1) 1) "121.48941010236740112"
   2) "31.40526993848380499"

获取两个key间直线距离

127.0.0.1:6379> geodist China:city beijing shanghai #后面可以跟单位,默认为m,
"1088644.3544"                                        #km,mi,ft
127.0.0.1:6379> geodist China:city beijing shanghai km
"1088.6444"

获取指定半径内的记录

#根据经纬度为中心
127.0.0.1:6379> georadius China:city 104 30 2000 km #单位为可选,默认m
1) "chengdu"      
2) "shanghai"
3) "beijing"
127.0.0.1:6379> georadius China:city 104 30 10000 km
1) "wulumuqi"
2) "chengdu"
3) "shanghai"
4) "beijing"
127.0.0.1:6379> georadius China:city 104 30 2000 km withdist #可选参数,附加距离
1) 1) "chengdu"
   2) "74.0411"
2) 1) "shanghai"
   2) "1678.1143"
3) 1) "beijing"
   2) "1587.8204"
127.0.0.1:6379> georadius China:city 104 30 2000 km withcoord #可选参数,附加经纬度
1) 1) "chengdu"
   2) 1) "104.10194188356399536"
      2) "30.65983886217613019"
2) 1) "shanghai"
   2) 1) "121.48941010236740112"
      2) "31.40526993848380499"
3) 1) "beijing"
   2) 1) "116.23128265142440796"
      2) "40.22076905438526495"
127.0.0.1:6379> georadius China:city 104 30 2000 km count 1 #可选参数,指定返回数量,距离小优先
1) "chengdu"
127.0.0.1:6379> georadius China:city 104 30 2000 km count 2
1) "chengdu"
2) "beijing"
#############################################################################################
#根据指定记录为中心
127.0.0.1:6379> geoRadiusByMember China:city chengdu 3000 km
1) "wulumuqi"
2) "chengdu"
3) "shanghai"
4) "beijing"
127.0.0.1:6379> geoRadiusByMember China:city chengdu 3000 km count 2 #限定个数
1) "chengdu"
2) "beijing"

获取所有key和删除key

geo底层是利用zset来实现的,可以使用zset的命令来操作geo

127.0.0.1:6379> zrange China:city 0 -1 #获取所有key
1) "wulumuqi"
2) "chengdu"
3) "shanghai"
4) "beijing"
127.0.0.1:6379> zrem China:city beijing #删除指定key
(integer) 1
127.0.0.1:6379> zrange China:city 0 -1
1) "wulumuqi"
2) "chengdu"
3) "shanghai"

Hyperloglog基数统计

用于储存一个集合的基数,占用内存比set小,固定占用12kb
与set相比有0.81%的错误率
127.0.0.1:6379> pfadd mykey a a b c d e f g#给一个基数添加值
(integer) 1
127.0.0.1:6379> pfcount mykey     #获取该集合的基数
(integer) 7
127.0.0.1:6379> pfadd mykey1 f g h j k m l n
(integer) 1
127.0.0.1:6379> pfcount mykey1
(integer) 8
127.0.0.1:6379> pfMerge mykey2 mykey mykey1 #将后面的集合合并为第一个集合
OK
127.0.0.1:6379> pfcount mykey2
(integer) 13
127.0.0.1:6379> pfcount mykey mykey1  #获取多个集合的基数
(integer) 13

Bitmap位图

bit储存形式是比特
1字节=8比特
127.0.0.1:6379> setbit mykey 0 0 #设置第0位的比特值为0,默认为0,可以直接设置1
(integer) 0                       #0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
127.0.0.1:6379> setbit mykey 1 0
(integer) 0
127.0.0.1:6379> setbit mykey 2 1
(integer) 0
127.0.0.1:6379> setbit mykey 3 1
(integer) 0
127.0.0.1:6379> setbit mykey 4 1
(integer) 0
127.0.0.1:6379> setbit mykey 5 1
(integer) 0
127.0.0.1:6379> setbit mykey 6 1
(integer) 0
127.0.0.1:6379> getbit mykey 1  #获取特定位的比特值
(integer) 0
##########################################################################
127.0.0.1:6379> bitcount mykey  #获取指定位图中比特值为1的个数
(integer) 5
127.0.0.1:6379> bitcount mykey 0 0 #限定字节下标,0代表0位到7位
(integer) 5
127.0.0.1:6379> bitcount mykey 1 1
(integer) 0

redid事务

redis命令有原子性,但是事务没有原子性
redis事务本质是一组命令的集合,一个事务中的所有命令会被序列化,在事务执行时按顺序执行。
一次性,顺序性,排他性的执行一组命令。
redis事务没有隔离级别的概念,所有命令在事务中不会输入后直接被执行,只有事务发起执行命令时才会执行。
redis事务流程:开启事务,命令入队,执行事务。
事务相关命令:
multi 开启事务
exec 执行事务
discard 取消事务
redis执行开启事务命令后,命令会依次进入事务队列,在进入队列前,会先进行命令正确性检查:
如果命令有语法错误,会报错,后续可以继续使命令入队,但是在最终执行事务时,事务会报错,不执行事务命令;
如果命令有逻辑性错误,例如对一个纯字母字符串执行了incr自增命令,该命令会顺利入队,不会检查出错误,在最终执行命令时,会报出错误,但是事务中的命令还是会执行,不会回滚
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 v2
QUEUED
127.0.0.1:6379(TX)> get k1
QUEUED
127.0.0.1:6379(TX)> exec   #执行事务
1) OK                        #事务输出
2) OK
3) "v1"
#############################################################
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set a1 v1
QUEUED
127.0.0.1:6379(TX)> set a2 v2
QUEUED
127.0.0.1:6379(TX)> discard      #取消事务
OK
127.0.0.1:6379> get a1
(nil)                              #事务中的命令没有被执行
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> set k4     #有语法错误
(error) ERR wrong number of arguments for 'set' command #检查失败,报错
127.0.0.1:6379(TX)> set k5 v5  #可以继续输入命令
QUEUED
127.0.0.1:6379(TX)> get k5
QUEUED
127.0.0.1:6379(TX)> exec
(error) EXECABORT Transaction discarded because of previous errors. #事务执行失败
127.0.0.1:6379> get k5  #事务并没有被执行
(nil)
127.0.0.1:6379> set k1 "v1"
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> incr k1  #k1是一个纯字母的字符串,有逻辑性错误
QUEUED                        #通过了语法检查,会进入命令队列
127.0.0.1:6379(TX)> set k2 aaa2
QUEUED
127.0.0.1:6379(TX)> get k2
QUEUED
127.0.0.1:6379(TX)> exec
1) (error) ERR value is not an integer or out of range  #该条命令报错
2) OK     #后续命令会继续执行
3) "aaa2" #没有回滚

redis实现乐观锁

悲观锁,认为在任何时候都会出现问题,需要锁定资源,不允许被其他线程改变;
乐观锁,认为在任何时候都不会出现问题,不需要上锁,在更新数据前判断一下数据是否被修改过,没有修改过就更新数据,更新过就不更新,中止事务

watch key [key] 监视一个或者多个key的命令,当监视变量后,执行事务前会先检查监视的变量是否被改变,被改变则取消事务,返回空值,没有改变就继续执行事务,成功执行事务后会自动取消监视key

unwatch 取消监视所有key

127.0.0.1:6379> set money 10
OK
127.0.0.1:6379> watch money #监视money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> decrby money 2
QUEUED
127.0.0.1:6379(TX)> incrby money 9
QUEUED
127.0.0.1:6379(TX)> exec   #执行事务成功,自动取消监视
1) (integer) 8
127.0.0.1:6379> get money
"17"
127.0.0.1:6379> watch money  #监视key
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> decrby money 29
QUEUED
127.0.0.1:6379(TX)> incrby money 7
QUEUED
127.0.0.1:6379(TX)> exec   #有其他线程改变了money的值,取消事务
(nil)
127.0.0.1:6379> unwatch  #取消监视key
OK

在springboot中整合reids

  1. 在maven中导入redis依赖

        <!--redis依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <!--        阿里的json依赖-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.83</version>
        </dependency>
  1. 在springboot配置文件中添加配置

spring:
  redis:
    host: 8.130.67.97 #远程数据库位置
    port: 6379  #数据库端口
    database: 1   #使用数据库编号
    password: 12345678 #数据库密码
  1. 添加配置类以自定义RedisTemplate类

用以实现java类型和java对象序列化,使在redis中显示时不会乱码
如果要想使自定义的实体类序列化,就需要自定义的实体类实现Serializable接口
RedisTemplate类中有很多与redis命令对于的api,用于操作redis
opsForValue 使用string相关的操作
opsForHash 使用Hash相关的操作
opsForList 使用List相关的操作
opsForSet 使用set相关的操作
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.StringRedisSerializer;

@Configuration
public class RedisConfig {

    @Bean
    @SuppressWarnings("all")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();

        template.setConnectionFactory(redisConnectionFactory);

        //配置序列化方式
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

        ObjectMapper obm=new ObjectMapper();
        // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和publi
        obm.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
        obm.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL);

        jackson2JsonRedisSerializer.setObjectMapper(obm);

        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        //key 采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        //hash
        template.setHashKeySerializer(stringRedisSerializer);
        //value
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
}
  1. 在springboot中测试

redis配置文件

redis的配置文件一般在redis安装目录中的redis文件夹内
requirepass 12345678   #设置redis连接密码
maxclients 10000    #设置redis的最大连接数
###############################################
# 1k => 1000 bytes
# 1kb => 1024 bytes
# 1m => 1000000 bytes
# 1mb => 1024*1024 bytes
# 1g => 1000000000 bytes
# 1gb => 1024*1024*1024 bytes   redis文件中大小单位
################################## INCLUDES ###################################
可以在这里配置导入其他redis的配置文件
# include /path/to/local.conf
# include /path/to/other.conf
################################## MODULES #####################################
可以在这里配置redis启动时运行的脚本,不能运行这个脚本则中止启动
# loadmodule /path/to/my_module.so
# loadmodule /path/to/other_module.so

网络设置

################################## NETWORK #####################################
#限定可以连接到redis的ip,注释后表示所有ip都可以访问
#bind 127.0.0.1    

#保护模式 yse/no  yes时,当redis未配置密码时,不允许未绑定的ip访问
protected-mode no  

#配置redis端口号
port 6379

#控制tcp三次握手 已完成连接队列 的长度
tcp-backlog 511

#一个连接空闲时间多长时断开连接,0表示无限
timeout 0

#每指定值秒最少发送一次信息给客户端,用以保持连接活跃
tcp-keepalive 300

控制设置

################################# GENERAL #####################################
#yes
#代表开启守护进程模式。在该模式下,redis会在后台运行,并将进程pid号写入至redis.conf选项
#pidfile设置的文件中,此时redis将一直运行,除非手动kill该进程。
#no
#exit强制退出或者关闭连接工具(putty,xshell等)都会导致redis进程退出。
daemonize yes

#如果需要在机器启动(upstart模式 或systemd模式)时就启动Redis服务器,可以通过该选项来配置Redis。
#supervised no - 不会与supervised tree进行交互
#supervised upstart - 将Redis服务器添加到SIGSTOP 模式中
#supervised systemd - 将READY=1 写入 $NOTIFY_SOCKET
#supervised auto - 根据环境变量UPSTART_JOB 或 NOTIFY_SOCKET检测upstart 还是 systemd
#上述 supervision 方法(upstart或systemd)仅发出“程序已就绪”信号,不会继续给supervisor返回ping回复
supervised no

#指定pid文件储存位置
#在redis启动时时尽力创建,若没有创建成功,不影响启动话会继续启动redis
#在redis停止时删除
pidfile /www/server/redis/redis.pid

#日志级别
#debug:会打印出很多信息,适用于开发和测试阶段
#verbose(冗长的):包含很多不太有用的信息,但比debug要清爽一些
#notice:适用于生产模式
#warning : 警告信息
loglevel notice

#日志文件位置
logfile "/www/server/redis/redis.log"

#数据库数量,索引从0开始
databases 16

#启动时是否显示logo
always-show-logo yes

持久化设置

rbd持久化

RDB:是Redis DataBase缩写。
按照一定的时间将内存的数据以快照的形式保存到硬盘中,对应产生的数据文件为dump.rdb。
生成快照的方式
BGSAVE:客户端可以使用BGSAVE命令来创建一个快照,当接收到客户端的BGSAVE命令时,redis会创建一个子进程,子进程负责将快照写入磁盘中,而父进程继续处理命令请求。(在子进程创建之初,父子进程共享相同内存,知道父进程或子进程对内存进行了写之后,对于被写入的内存的共享就会结束服务)

SAVE:客户端使用SAVE命令创建一个快照,接收到SAVE命令的redis服务器在快照创建完毕之前将不再响应任何其他的命令。

配置文件:服务器通过配置方式来满足自动触发快照进行持久化,管理员需要在redis.conf中设置save配置选项,redis会在save选项条件满足之后自动触发一次BGSAVE命令,如果管理员设置了多个save配置选项,当任意save条件被满足,redis都会触发一次BGSAVE命令。

shutdown指令:当redis通过shutdown指令接受到关闭服务器的请求时,会触发一次SAVE命令,阻塞所有的客户端,不再执行客户端发送的任何命令,在SAVE命令执行完毕后关闭服务器。
优点
只有一个dump.rdb文件,方便持久化
容灾性好,一个文件可以保存到安全的磁盘中。
性能最大化,子进程来完成写操作,主进程可以继续处理命令,实现IO最大化(使用单独的子进程来进行持久化,主进程不会进行任何IO操作,保证了redis的高性能)。
相对于数据集大时,比AOF的启动效率更高。
缺点
数据安全性第。RDB是间隔一段时间进行持久化,如果持久化之间redis发生故障,会发生数据丢失。
dump.rdb文件是一个redis中特制的二进制文件,涉及到不同的redis版本,可能会发生版本不兼容问题。
################################ SNAPSHOTTING  ################################
#save <秒> <数据库改变次数>
#设置数据库没多少秒改变多少次就进行rbd持久化操作
#全部注释后可以关闭rbd持久化

save 900 1
save 300 10
save 60 10000

#在持久化错误时是否停止写入新的数据
stop-writes-on-bgsave-error yes

#储存rbd文件时是否压缩
rdbcompression yes

#在储存rbd文件时,是否开启crc64算法进行校验数据
#开启后将会多消耗10%的性能
rdbchecksum yes

#rbd文件名字
dbfilename dump.rdb

#持久化文件储存路径
dir /www/server/redis/

aof持久化

AOF:是Append Only File的缩写。
是指,将redis执行的所有写命令记录到日志文件中,将被执行的写命令写到AOF的文件末尾,当redis重启时,redis会从头到尾执行一次AOF文件所包含的所有写命令,以此回复AOF文件的记录的数据集。
aof重写流程
重写AOF的时候,创建一个重写子进程,然后读取旧的AOF文件,压缩并写入到一个临时AOF。

在此期间,主进程一边将接收到的指令累计到一个缓冲区中,一边将指令写入到旧的AOF。
(这样的好处,保证AOF文件的可用性,避免写过程时出意外)

子进程写完后,向主进程发送一个信号量,主进程就将缓冲区中的指令追加到新AOF。

用新的AOF替换旧的AOF,之后的新指令就追加到新的AOF。
命令触发重写
执行BGREWRITEAOF命令 不会阻塞redis服务
优点
数据安全,AOF持久化可以通过配置appendfsync属性,设置其记录频率。
通过append模式写文件,即使服务器宕机,也可以通过redis-check-aof工具解决数据一致问题。
更加灵活。AOF机制的 rewrite 模式,AOF文件没被rewrite之前(文件过大时回对命令进行合并重写),可以删除其中的某些命令。
缺点
AOF文件比RDB文件更大,且回复速度更慢。
数据集大时,AOF比RDB启动效率低。
当RDB和AOF同时开启时,redis数据恢复会优先选中AOF恢复。
############################## APPEND ONLY MODE ###############################
#是否开启aof持久化
appendonly no

#aof持久化文件名字
appendfilename "appendonly.aof"

# appendfsync always   每次改变数据库都将命令保存到aof文件
appendfsync everysec   #每秒保存一次aof文件从缓存区到磁盘
# appendfsync no       #由操作系统判断保存时机

#在重写aof文件时是否禁止保存aof文件从缓存区到磁盘
#no 禁止,会阻塞其余对磁盘操作的线程        如果应用系统无法忍受数据丢失
#yes 不禁止,会造成aof文件少量数据丢失     如果应用系统无法忍受延迟,而可以容忍少量的数据丢失
no-appendfsync-on-rewrite no

#aof文件重写,会压缩aof文件,例如去除不必要的更新命令
#当目前aof文件大小超过上一次重写的aof文件大小的百分之多少进行重写
auto-aof-rewrite-percentage 100  
auto-aof-rewrite-min-size 64mb  #当aof文件占多少磁盘时第一次重写aof文件

#当Redis启动时,发现AOF文件出现末尾截断,这时是继续加载文件还是报错退出
#yes :末尾被截断的 AOF 文件将会被加载,并打印日志通知用户;
#no : 服务器将报错并拒绝启动;(可以通过使用redis-check-aof 
#      工具修复AOF文件,然后再重新启动)
aof-load-truncated yes

#同时使用rbd,aof持久化
aof-use-rdb-preamble yes

消息订阅发布

Redis 发布订阅 | 菜鸟教程 (runoob.com)

redis主从复制

(3条消息) Redis——Redis主从复制(工作流程详解)_stan Z的博客-CSDN博客

在配置文件中配置

################################# REPLICATION #################################
#设置主机ip和端口,设置后该台redis服务器就变成了从机
# replicaof <masterip> <masterport>
replicaof 127.0.0.1 6379

#设置主机密码,如果主机有密码,只有设置对了密码才能连接上主机
# masterauth <master-password>
masterauth 12345678

在命令行查看状态

#主机状态
127.0.0.1:6379> info replication
# Replication
role:master  #当前服务器是主机
connected_slaves:2 #当前主机的从机数量
slave0:ip=127.0.0.1,port=6381,state=online,offset=244,lag=1 #从机详细信息
slave1:ip=127.0.0.1,port=6382,state=online,offset=244,lag=0
master_failover_state:no-failover
master_replid:3c8383d066474632d0ea0585cc7bf699ea2042b0
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:244
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:244
#查看从机信息
127.0.0.1:6381> info replication
# Replication
role:slave
master_host:127.0.0.1 #主机ip
master_port:6379      #主机端口
master_link_status:up  #主机是否在线
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_read_repl_offset:160
slave_repl_offset:160
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:3c8383d066474632d0ea0585cc7bf699ea2042b0
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:160
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:77
repl_backlog_histlen:84

redis哨兵

Redis哨兵(Sentinel)模式 - 简书 (jianshu.com)
配置哨兵配置文件sentinel.conf,没有就创建
  • redis启用哨兵模式后,应该将所有主机从机都设置一个同样的密码,并且设置和访问密码一样的主机密码,否则会出现选出新主机时,旧主机连接新主机没有密码。导致不停连接主机,使日志文件爆满磁盘的情况

  • reid哨兵在选出新的主机时,会给集群中的所有redis发送更换新主机的消息

  • 收到消息的从机会在配置文件修改配置信息

  • 新主机会删除配置文件中配置主机的命令

  • 旧主机会在配置文件最后一行追加配置主机信息

# 禁止保护模式
protected-mode no

#sentinel monitor 被监控的主机名字(自定义) IP 端口 被判断多少次不在线就从 从机 中更换主机
sentinel monitor myredis 127.0.0.1 6379 1

# sentinel author-pass定义服务的密码,mymaster是服务名称,123456是Redis服务器密码
# sentinel auth-pass <master-name> <password>
sentinel auth-pass myredis 12345678

运行成功后命令行显示

[ecs-user@iZi905odmgazwoZ redis]$ sudo redis-sentinel sentiel.conf
192527:X 31 Mar 2023 22:49:57.402 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
192527:X 31 Mar 2023 22:49:57.402 # Redis version=7.0.5, bits=64, commit=00000000, modified=0, pid=192527, just started
192527:X 31 Mar 2023 22:49:57.402 # Configuration loaded
192527:X 31 Mar 2023 22:49:57.403 * monotonic clock: POSIX clock_gettime
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 7.0.5 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                  
 (    '      ,       .-`  | `,    )     Running in sentinel mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 26379
 |    `-._   `._    /     _.-'    |     PID: 192527
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           https://redis.io       
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               

192527:X 31 Mar 2023 22:49:57.407 * Sentinel new configuration saved on disk
192527:X 31 Mar 2023 22:49:57.407 # Sentinel ID is ac54764e7876b86c3fad93f05ab23b1dc95a8c61
192527:X 31 Mar 2023 22:49:57.407 # +monitor master myredis 127.0.0.1 6379 quorum 1

#从机列表
192527:X 31 Mar 2023 22:49:57.407 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379
192527:X 31 Mar 2023 22:49:57.410 * Sentinel new configuration saved on disk
192527:X 31 Mar 2023 22:49:57.410 * +slave slave 127.0.0.1:6382 127.0.0.1 6382 @ myredis 127.0.0.1 6379
192527:X 31 Mar 2023 22:49:57.413 * Sentinel new configuration saved on disk

在springboot中配置哨兵使用

yml配置
spring:
  redis:
    # 数据库(默认为0号库)
    # database: 2
    # 密码(默认空),操作redis需要使用的密码
    password: 12345678
    # 端口号
    # port: 6379
    #连接超时时间(毫秒)
    timeout: 10000ms
    sentinel:
      master: mymaster
      nodes:
        - 192.168.229.200:26379
        - 192.168.229.201:26379
        - 192.168.229.202:26379
      # 操作sentinel时需要提供的密码
      password: 12345678
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值