目录
1、认识Redis
Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
Redis能干嘛?
1、内存存储、持久化,内存中的数据是断电即失的,所以持久化很重要(RDB、AOF)
2、效率高,可以用于高速缓存
3、发布订阅系统
4、地图信息分析
5、计时器、计数器(浏览量)
6、……
特性
1、多样的数据类型
2、持久化
3、集群
4、事务
……
2、基础知识
1、redis默认有16个数据库,默认使用的是第0个数据库,可以使用select切换数据库
select 1 #切换1数据库
DBSIZE #查看DB大小
keys * #查看所有key
flushall #清空所有数据库
flushdb #清空当前数据库
exists key #判断当前key是否存在
move key 1 #移除当前的key
expire key second #设置过期时间
ttl key #查看key剩余过期时间
type key #查看key的类型
Redis是单线程的
官方表示,Redis是基于内存操作的,CPU不是Redis的性能瓶颈。Redis的瓶颈是根据机器的内存和网络带宽,既然可以使用单线程,就使用单线程了
Redis是C语言写的,官方提供的数据为100000+的QPS,完全不比同样使用key-value的MemeCache差
Redis为什么单线程还这么快?
误区1:高性能服务器一定是多线程的
误区2:多线程(CPU上下文切换)一定比单线程效率高
速度:CPU>内存>硬盘
核心:redis是将全部数据放在内存中,所以使用单线程去操作效率就是最高的,对于内存系统来说,如果没有上下文切换效率就是最高的,多次读写都是在一个CPU上。
3、Redis五大数据类型
1、String
set key value #设置key-value
get key #获取key的value
exists key #key是否存在
append key value #追加字符串,若key不存,相当于set key value
strlen key #获取字符串长度
incr key #当前key的value加1
decr key #当前key的value减一
incrby key 10 #当前key加10
decrby key 10 #当前key减10
getrange key 0 3 #字符串范围 (getrange key 0 -1 获取全部字符串)
setrange key 1 xx #替换指定位置开始的字符串
setex key second value #(set with expire)设置过期时间
setnx key value #(set if not with exists )不存在再设置 (分布式锁中常使用)
mset key1 v1 key2 v2 #批量设置
mget key1 key2 key3 #批量获取
msetnx key1 v1 key2 v2 #不存在再设置(批量 原子性操作 一起成功 一起失败)
getset key value #先获取原值再设置新值
127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> set name lqh
OK
127.0.0.1:6379> keys *
1) "name"
127.0.0.1:6379> set age 1
OK
127.0.0.1:6379> keys * #查看所有的key
1) "age"
2) "name"
127.0.0.1:6379> EXISTS key
(integer) 0
127.0.0.1:6379> EXISTS name #判断当前key是否存在
(integer) 1
127.0.0.1:6379> move name 1 #将key移动到1号数据库中
(integer) 1
127.0.0.1:6379> keys *
1) "age"
127.0.0.1:6379> set name 123
OK
127.0.0.1:6379> keys *
1) "name"
2) "age"
127.0.0.1:6379> EXPIRE name 10 #设置key过期的时间,单位是秒
(integer) 1
127.0.0.1:6379> ttl name #查看当前key的剩余时间
(integer) 6
127.0.0.1:6379> set name lqh
OK
127.0.0.1:6379> keys *
1) "name"
2) "age"
127.0.0.1:6379> TYPE name #查看当前key对应value的类型
string
127.0.0.1:6379> TYPE age
string
127.0.0.1:6379> set key1 v1 #设置值
OK
127.0.0.1:6379> get key1 #获得值
"v1"
127.0.0.1:6379> keys * #获得所有key
1) "key1"
2) "name"
3) "age"
127.0.0.1:6379> EXISTS key1 #判断某一个key是否存在
(integer) 1
127.0.0.1:6379> APPEND key1 "hello" #追加字符串,如果key不存在就相当于set key
(integer) 7
127.0.0.1:6379> get key1
"v1hello"
127.0.0.1:6379> APPEND key1 ",nihao"
(integer) 13
127.0.0.1:6379> STRLEN key1 #获取字符串长度
(integer) 13
127.0.0.1:6379> get key1
"v1hello,nihao"
#步长
127.0.0.1:6379> set views 0
OK
127.0.0.1:6379> get views
"0"
127.0.0.1:6379> incr views #自增一
(integer) 1
127.0.0.1:6379> incr views
(integer) 2
127.0.0.1:6379> get views
"2"
127.0.0.1:6379> decr views #自减一
(integer) 1
127.0.0.1:6379> decr views
(integer) 0
127.0.0.1:6379> decr views
(integer) -1
127.0.0.1:6379> get views
"-1"
127.0.0.1:6379> INCRBY views 10 #设置步长,指定增量
(integer) 9
127.0.0.1:6379> DECRBY views 5 #设置步长,指定减量
(integer) 4
127.0.0.1:6379> get views
"4"
#字符串范围
127.0.0.1:6379> set key1 "hello,lqh" #设置key的值
OK
127.0.0.1:6379> get key1
"hello,lqh"
127.0.0.1:6379> GETRANGE key1 0 3 #截取字符串 [0,3]
"hell"
127.0.0.1:6379> GETRANGE key1 0 -1 #获取全部的字符串 和get key是一样的
"hello,lqh"
#替换
127.0.0.1:6379> set key2 abcdefg
OK
127.0.0.1:6379> get key2
"abcdefg"
127.0.0.1:6379> SETRANGE key2 1 xx #替换指定位置开始的字符串
(integer) 7
127.0.0.1:6379> get key2
"axxdefg"
#setex key #(set with expire)设置过期时间
#setnx key #(set if not with exists )不存在再设置 在分布式锁中会常使用
127.0.0.1:6379> setex key3 30 "hello" #设置一个key3的值为hello,30秒后过期
OK
127.0.0.1:6379> ttl key3
(integer) 19
127.0.0.1:6379> setnx mykey "redis" #如果mykey不存在,创建mykey
(integer) 1
127.0.0.1:6379> keys *
1) "mykey"
2) "key1"
3) "key2"
127.0.0.1:6379> ttl key3
(integer) -2
127.0.0.1:6379> setnx mykey "hello" #如果mykey存在,创建失败
(integer) 0
127.0.0.1:6379> get mykey
"redis"
mset key1 v1 key2 v2 #批量设置
mget key1 key2 key3 #批量获取
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 #同时设置多个值
OK
127.0.0.1:6379> keys *
1) "k2"
2) "k3"
3) "k1"
127.0.0.1:6379> mget k1 k2 k3 #同时获取多个值
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> msetnx k1 v1 k4 v4 #msetnx是一个原子性的操作,要么一起成功要么一起失败
(integer) 0
127.0.0.1:6379> get k4
(nil)
#对象
set user:1 {name:zhangsan,age:2} #设置一个user:1对象,值为json字符来保存一个对象
#这里的key是一个巧妙的设计:user:{id}:{filed},如此设计在redis中是完全ok的
127.0.0.1:6379> mset user:1:name zhangsan user:1:age 2
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "zhangsan"
2) "2"
getset #先get再set
127.0.0.1:6379> getset db redis #如果不存在值则返回nil
(nil)
127.0.0.1:6379> get db
"redis"
127.0.0.1:6379> getset db Mongodb #如果存在值,获取原来的值并设置新的值
"redis"
127.0.0.1:6379> get db
"Mongodb"
数据结构是相同的
String类似的使用场景:value除了是我们的字符串还可以使我们的数字(计数器、统计多单位数量、粉丝数、对象缓存存储)
2、List
Redis中,可以将list用作栈、队列、阻塞队列的数据结构
所有list命令都是以l开头
lpush key v1 v2 ... #将一个值或多个值插入列表的头部(左)
rpush key v1 v2 ... #将一个值或多个值插入列表的尾部(右)
lrange key start end #用过区间获取具体的值 (0 -1 区间获取全部值)
lpop key #移除列表头部第一个值(左)
rpop key #移除列表尾部第一个值(右)
lindex key index #通过索引获取值
llen key #获取列表长度
lrem key count value #移除list集合中指定个数的value 精确匹配
ltrim key start stop #通过下标截取指定长度,list已经改变,只剩下截取后的元素
rpoplpush key otherkey #移除列表中最后一个元素,并将它插入另一个列表头部
lset key index value #将列表中指定下标的值替换为另外一个值,更新操作 (如果列表或索引不存在 会报错)
linsert key before v1 v2 #在v1前插入v2
linsert key after v1 v2 #在v1后插入v2
127.0.0.1:6379> LPUSH list one #将一个或者多个值,插入到列表的头部(左边)
(integer) 1
127.0.0.1:6379> LPUSH list twe
(integer) 2
127.0.0.1:6379> LPUSH list three
(integer) 3
127.0.0.1:6379> LRANGE list 0 -1 #获取list中的值
1) "three"
2) "twe"
3) "one"
127.0.0.1:6379> LRANGE list 0 1 #通过区间获取list中具体的值
1) "three"
2) "twe"
127.0.0.1:6379> RPUSH list right #将一个或者多个值,插入到列表的尾部(右边)
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "twe"
3) "one"
4) "right"
#LPOP
#RPOP
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "twe"
3) "one"
4) "right"
127.0.0.1:6379> LPOP list #移除list的第一个元素
"three"
127.0.0.1:6379> RPOP list #移除list的最后一个元素
"right"
127.0.0.1:6379> LRANGE list 0 -1
1) "twe"
2) "one"
#lindex
127.0.0.1:6379> LRANGE list 0 -1
1) "twe"
2) "one"
127.0.0.1:6379> LINDEX list 1 #通过下标获得list中的某一个值
"one"
127.0.0.1:6379> LINDEX list 0
"twe"
127.0.0.1:6379> Lpush list one
(integer) 1
127.0.0.1:6379> Lpush list twe
(integer) 2
127.0.0.1:6379> Lpush list three
(integer) 3
127.0.0.1:6379> Llen list #返回列表长度
(integer) 3
#移除指定的值
127.0.0.1:6379> Lpush list one
(integer) 1
127.0.0.1:6379> Lpush list twe
(integer) 2
127.0.0.1:6379> Lpush list three
(integer) 3
127.0.0.1:6379> Llen list
(integer) 3
127.0.0.1:6379> Lpush list three
(integer) 4
127.0.0.1:6379> lrem list 1 one #移除list集合中指定个数的valus,精确匹配
(integer) 1
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "three"
3) "twe"
127.0.0.1:6379> lrem list 1 three
(integer) 1
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "twe"
127.0.0.1:6379> Lpush list three
(integer) 3
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "three"
3) "twe"
127.0.0.1:6379> lrem list 2 three
(integer) 2
127.0.0.1:6379> LRANGE list 0 -1
1) "twe"
#ltrim 修剪
127.0.0.1:6379> Lpush mylist "hello"
(integer) 1
127.0.0.1:6379> Lpush mylist "hello1"
(integer) 2
127.0.0.1:6379> Lpush mylist "hello2"
(integer) 3
127.0.0.1:6379> Lpush mylist "hello3"
(integer) 4
127.0.0.1:6379> ltrim mylist 1 2 #只截取区间内的,剩余的将全部被删除
OK
127.0.0.1:6379> LRANGE mylist 0 -1
1) "hello2"
2) "hello1"
rpoplpush #移除列表中最后一个元素,并将它移动到新的列表中
127.0.0.1:6379> lpush list "hello"
(integer) 1
127.0.0.1:6379> lpush list "hello1"
(integer) 2
127.0.0.1:6379> lpush list "hello2"
(integer) 3
127.0.0.1:6379> rpoplpush list mylist #移除列表中最后一个元素,并将它移动到新的列表中
"hello"
127.0.0.1:6379> lrange list 0 -1 #查看原来的列表
1) "hello2"
2) "hello1"
127.0.0.1:6379> lrange mylist 0 -1 #查看目标列表中却是存在该值
1) "hello"
lset #将列表中指定下标的值替换为另外一个值
127.0.0.1:6379> EXISTS list #判断这个列表是否存在
(integer) 0
127.0.0.1:6379> lset list 0 item #如果不存在我们去更新就会报错
(error) ERR no such key
127.0.0.1:6379> lpush list value1
(integer) 1
127.0.0.1:6379> lrange list 0 0
1) "value1"
127.0.0.1:6379> lset list 0 item #如果存在则更新下标的值
OK
127.0.0.1:6379> lrange list 0 0
1) "item"
127.0.0.1:6379> lset list 1 other #如果不存在就会报错
(error) ERR index out of range
linsert #将某个具体的value插入到列表中某个元素的前面或者后面
127.0.0.1:6379> rpush list hello
(integer) 1
127.0.0.1:6379> rpush list world
(integer) 2
127.0.0.1:6379> LINSERT list before "world" "other" #在world前插入other
(integer) 3
127.0.0.1:6379> LRANGE list 0 -1
1) "hello"
2) "other"
3) "world"
127.0.0.1:6379> lpush mylist hello
(integer) 1
127.0.0.1:6379> lpush mylist world
(integer) 2
127.0.0.1:6379> LINSERT mylist before "world" "other"
(integer) 3
127.0.0.1:6379> LRANGE list 0 -1
1) "hello"
2) "other"
3) "world"
127.0.0.1:6379> LRANGE mylist 0 -1
1) "other"
2) "world"
3) "hello"
127.0.0.1:6379> LINSERT list after "world" "123" #在world后插入123
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
1) "hello"
2) "other"
3) "world"
4) "123"
3、Set
set中的值不能重复
sadd key value #添加元素
smembers key #查看指定set中所用元素
sismember key value #判断某一个值在指定set中是否存在
scard key #获取set中的内容元素个数
srem key value #移除set中指定元素
srandmember key count #随机选出指定个数的成员
spop key #随机移除元素
smove oldkey newkey member #将一个指定的值,从一个set移动到另一个set
sdiff key... #获取多个set差集
sinter key... #获取多个set交集 (共同好友、共同关注)
sunion key... #获取多个set并集
127.0.0.1:6379> sadd myset hello #添加元素
(integer) 1
127.0.0.1:6379> sadd myset world
(integer) 1
127.0.0.1:6379> sadd myset 123
(integer) 1
127.0.0.1:6379> SMEMBERS myset #查看指定set中所用元素
1) "123"
2) "world"
3) "hello"
127.0.0.1:6379> SISMEMBER myset hello #判断某一个值在指定set中是否存在
(integer) 1
127.0.0.1:6379> SISMEMBER myset lqh
(integer) 0
127.0.0.1:6379> SCARD myset #获取set集合里元素的个数
(integer) 3
127.0.0.1:6379> srem myset 123 #移除set中的指定
(integer) 1
127.0.0.1:6379> SCARD myset
(integer) 2
127.0.0.1:6379> SMEMBERS myset
1) "world"
2) "hello"
127.0.0.1:6379> SRANDMEMBER myset #随机选出指定个数的成员
"world"
127.0.0.1:6379> SRANDMEMBER myset
"hello"
127.0.0.1:6379> SRANDMEMBER myset
"hello"
127.0.0.1:6379> SRANDMEMBER myset
"world"
127.0.0.1:6379> SMEMBERS myset
1) "def"
2) "abc"
3) "world"
4) "hello"
127.0.0.1:6379> spop myset #随机移除元素
"def"
127.0.0.1:6379> spop myset
"hello"
#将一个指定的值,从一个set移动到另一个set
127.0.0.1:6379> sadd myset hello
(integer) 1
127.0.0.1:6379> sadd myset world
(integer) 1
127.0.0.1:6379> sadd myset lqh
(integer) 1
127.0.0.1:6379> sadd myset2 set2
(integer) 1
127.0.0.1:6379> smove myset myset2 lqh #将一个指定的值,从一个set移动到另一个set集合中
(integer) 1
127.0.0.1:6379> SMEMBERS myset
1) "world"
2) "hello"
127.0.0.1:6379> SMEMBERS myset2
1) "set2"
2) "lqh"
127.0.0.1:6379> sadd key1 1
(integer) 1
127.0.0.1:6379> sadd key1 2
(integer) 1
127.0.0.1:6379> sadd key1 3
(integer) 1
127.0.0.1:6379> sadd key2 3
(integer) 1
127.0.0.1:6379> sadd key2 4
(integer) 1
127.0.0.1:6379> sadd key2 5
(integer) 1
127.0.0.1:6379> sadd key2 6
(integer) 1
127.0.0.1:6379> SDIFF key1 key2 #差集
1) "1"
2) "2"
127.0.0.1:6379> SINTER key1 key2 #交集 共同好友可以这么实现
1) "3"
127.0.0.1:6379> SUNION key1 key2 #并集
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
应用场景:微博,将用户所有关注放入一个set,粉丝放入一个set
-> 共同关注、二度好友、相互关注…..
4、Hash
Map集合 key-(key-value)
hs