一、基础知识
在Redis中默认有16个数据库
使用vim xconfig/redis.conf 查看redis的配置文件,可以看到默认数据库数量,通过修改配置文件来修改默认数据库数量
默认使用的是第0个数据库
我们可以通过select命令切换数据库
127.0.0.1:6379> select 3
OK
127.0.0.1:6379[3]> dbsize #查看数据库大小
(integer) 0
127.0.0.1:6379[3]> keys * # 查看当前数据库所有的key
1) "name"
2) "age"
127.0.0.1:6379[3]>
清除当前数据库: flushdb
127.0.0.1:6379[3]> flushdb
OK
127.0.0.1:6379[3]> dbsize
(integer) 0
清除全部数据库内容:flushall
127.0.0.1:6379[3]> flushall
OK
127.0.0.1:6379[3]> dbsize
(integer) 0
127.0.0.1:6379[3]> select 2
OK
127.0.0.1:6379[2]> dbsize
(integer) 0
127.0.0.1:6379[2]> select 0
OK
127.0.0.1:6379> dbsize
(integer) 0
Redis是单线程的
官方表示,Redis是基于内存操作,CPU不是Redis性能瓶颈,Redis的瓶颈是根据机器的内存和网络宽带,既然可以使用单线程来实现,就使用单线程
Redis为什么那么快?
1.误区一:高性能的服务器一定是多线程的?
2.误区二:多线程(CPU上下文会切换)一定比单线程效率高!
核心:redis是将所有的数据全部放在内存中的,所有说使用单线程去操作效率就是最高的,多线程(CPU上下文会切换:耗时操作),对于内存系统来说,如果没有上下文切换效率就是最高的。
二、五大数据类型
1.Redis-key的常用命令
命令 | 描述 |
---|---|
EXISTS key | 检查key是否存在 |
EXPIREkey seconds | 为指定key设置过期时间,单位(秒) |
KEYS pattern | 按照指定格式查找key |
MOVE key db | 将当前数据库的key的移动到指定数据库中 |
TTL key | 以秒为单位返回key的过期时间 |
TYPE key | 返回key的数据类型 |
RENAME key newkey | 修改key的名字 |
DEL key | 当key存在时,删除key |
常用命令的测试
2.Strings(字符串)常用指令
命令 | 描述 |
---|---|
SET key value | 将key设定为指定字符串值 |
GET key | 获取指定key的值 |
APPEND key value | 往key的末尾追加值,如果key不存在就先创建key |
INCR key | 对key所存储的值进行原子加1操作,如果key不存在,就在操作之前创建key并设置为0(自增1) |
DECR key | 对key对应的数字做减1操作。如果key不存在,那么在操作之前,这个key对应的值会被置为0(自减1) |
INCRBY key number | 将key对应的数字加上number。如果key不存在,操作之前,key就会被置为0 |
DECRBY key number | 将key对应的数字减去number。如果key不存在,操作之前,key就会被置为0 |
STRLEN key | key对应的字符串value的长度,或者0(key不存在) |
注意:incr、decr、incrby、decrby这些命令会将字符串值解析成整形,如果指定的key中存储的值不是字符串类型(fix:)或者存储的字符串类型不能表示为一个整数,
那么执行这个命令时服务器会返回一个错误(eq:(error) ERR value is not an integer or out of range)
测试常用命令
127.0.0.1:6379> set key1 10 # 设置key1的值为10
OK
127.0.0.1:6379> get key1 # 获取key1的值
"10"
127.0.0.1:6379> append key1 10 #在key1的末尾追加10这个字符串
(integer) 4
127.0.0.1:6379> get key1
"1010"
127.0.0.1:6379> append key2 zhangsan
(integer) 8 # 当前没有key2,所以先创建之后再在key2的默认追加zhangsan
127.0.0.1:6379> get key2
"zhangsan"
127.0.0.1:6379> incr key1 # key1的值自增1
(integer) 1011
127.0.0.1:6379> decr key1 # key1的值自减1
(integer) 1010
127.0.0.1:6379> incrby key1 20 # key1的值加上20
(integer) 1030
127.0.0.1:6379> decrby key1 30 # key1的值减去20
(integer) 1000
127.0.0.1:6379> strlen key1 # key1的值的字符串长度为4
(integer) 4
字符串范围类型的命令(range)
命令 | 描述 |
---|---|
GETRANGE key start end | 根据指定的范围返回key对应的字符串值。可以用负数表示string尾巴下标,-1就是最后一个。(注意:当指定范围超出string长度,都把结果限制在string内。) |
SETRANGE key offsett value | 覆盖key对应的string的一部分,从指定的offset处开始,覆盖value的长度。如果offset比当前key对应string还要长,那这个string后面就补0以达到offset。 |
测试命令
# 我们先设置key2的值为hello world
127.0.0.1:6379> set key2 "hello world"
OK
127.0.0.1:6379> get key1
"1000"
# 打印出hello 注意:第一个是从0开始,最后一个是从-1开始
127.0.0.1:6379> GETRANGE key2 0 4
"hello"
# 打印出key2所对应的值
127.0.0.1:6379> GETRANGE key2 0 -1
"hello world"
# 将"hello world" 修改成"hello redis"
127.0.0.1:6379> SETRANGE key2 6 redis
(integer) 11
127.0.0.1:6379> get key2
"hello redis"
set的衍生命令
命令 | 描述 |
---|---|
SETEX key seconds value | 设置key对应字符串value,并且设置key在给定的seconds时间之后超时过期,单位为秒 |
SETNX key value | 将key设置值为value,如果key不存在,这种情况下等同SET命令。 当key存在时,什么也不做。SETNX是”SET if Not eXists”的简写。 |
# 设置key2的值为10,因为已经存在所以无法创建,返回0
# 此方法如果成功返回1,失败返回0
127.0.0.1:6379> setnx key2 10
(integer) 0
127.0.0.1:6379> setnx key3 "xiao"
(integer) 1
# 为key2设置一个过期时间
127.0.0.1:6379> setex key2 10 "li"
OK
# 显示过期时间
127.0.0.1:6379> ttl key2
(integer) 7
批量处理的命令
命令 | 描述 |
---|---|
MSET | 对应给定的keys到他们相应的values上。MSET是原子的,所以所有给定的keys是一次性set的。客户端不可能看到这种一部分keys被更新而另外的没有改变的情况。 |
MGET | 返回所有指定的key的value。对于每个不对应string或者不存在的key,都返回特殊值nil |
MSETNX | 对应给定的keys到他们相应的values上。只要有一个key已经存在,MSETNX一个操作都不会执行 |
# 同时设置多个值
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"
# msetnx是一个原子操作,要么都成功,要么都失败
127.0.0.1:6379> MSETNX k1 f k4 fsd
(integer) 0
# 因为k1已经存在值,所以执行失败
127.0.0.1:6379> get k1
"v1"
set的高阶用法
# 对象
# 设置一个key为user:1 值为json字符来保存一个对象
127.0.0.1:6379> set user:1 {name:zhangsan,age:3}
OK
# 这里的key是一个巧妙的设计:user:{id}:{filed},如此设计再Redis是可以的
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"
Strings 的使用场景:value除了是字符串还可以是数字!
- 计数器
- 统计多单位的数量
- 粉丝数
- 对象缓存存储
3.Lists(列表)数据类型的常用命令
在Redis中,List可以通过指令实现栈、队列、阻塞队列。
Lists的大部分命令都是以L开头。
命令 | 描述 |
---|---|
LPUSH | 往列表的左边也就是头部插入一条元素(left push) |
RPUSH | 往列表的右边也就是尾部插入一条元素(right push) |
LRANGE | 返回存储在列表中指定范围的元素,从0开始计算,也可以是负数,-1代表最后一个,以此类推 |
LPOP | 移除并且返回列表的第一个元素。 |
RPOP | 移除并返回存于列表的最后一个元素。 |
LINDEX | 通过index索引去返回列表中的值 |
LLEN | 返回列表的长度 |
LREM | 从列表中移除出现了指定数量和指定value的元素 |
LTRIM | 通过下标截取指定长度的列表 |
RPOPLPUSH | 移除列表最后一个元素,并将它添加到一个新的列表中的第一个 |
LSET | 通过下标设置列表中的值,可以当作更新操作,当下标大于元素的数量将会报错 |
LINSERT | 将某个具体的value插入到列表中某个元素的前面或者后面 |
# 先清除以下之前测试留下的数据
127.0.0.1:6379> flushdb
OK
# 将多个数值插入到列表的头部
127.0.0.1:6379> LPUSH list one two three
(integer) 3
# 查看列表中所有的元素
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
# 查看指定范围的元素
127.0.0.1:6379> LRANGE list 0 1
1) "three"
2) "two"
# 向列表的尾部插入元素
127.0.0.1:6379> RPUSH list four
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
4) "four"
=====================================================
# 将列表中第一个元素移除
127.0.0.1:6379> LPOP list
"three"
127.0.0.1:6379> LRANGE list 0 -1
1) "two"
2) "one"
3) "four"
# 将列表中最后一个元素移除
127.0.0.1:6379> rpop list
"four"
127.0.0.1:6379> LRANGE list 0 -1
1) "two"
2) "one"
====================================================
# 返回第一个元素
127.0.0.1:6379> LINDEX list 0
"two"
# 没有第五个元素,返回nil
127.0.0.1:6379> LINDEX list 4
(nil)
====================================================
# list长度为2
127.0.0.1:6379> LLEN list
(integer) 2
=====================================================
# 我们先往列表里加一下数据用来测试
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "two"
5) "three"
6) "four"
7) "five"
8) "five"
# 从list的头部向尾部移除等于"two"的元素
# 当count>0时,从头往尾移除count个指定value的元素
# 当count<0时,从尾往头移除count个指定value的元素
# 当count=0时,移除所有指定value的元素
127.0.0.1:6379> lrem list 2 two
(integer) 2
# 移除后的列表
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "one"
3) "three"
4) "four"
5) "five"
6) "five"
=====================================================
# 截取3~4之间的元素
127.0.0.1:6379> LTRIM list 2 3
OK
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "four"
=====================================================
# 新建两个列表,source和destination,往列表右边插入一些元素
127.0.0.1:6379> RPUSH source a b c
(integer) 3
127.0.0.1:6379> RPUSH destination x y z
(integer) 3
# 使用RPOPLPUSH 将source列表最后一个元素转移到destination的第一个
127.0.0.1:6379> RPOPLPUSH source destination
"c"
127.0.0.1:6379> LRANGE source 0 -1
1) "a"
2) "b"
127.0.0.1:6379> LRANGE destination 0 -1
1) "c"
2) "x"
3) "y"
4) "z"
# 当源列表和目标列表是同一个时,会将此列表的最后一个转移到第一个
127.0.0.1:6379> RPOPLPUSH source source
"b"
127.0.0.1:6379> LRANGE source 0 -1
1) "b"
2) "a"
# 当源列表不存在,将返回nil值
127.0.0.1:6379> RPOPLPUSH yx source
(nil)
=====================================================
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "four"
# 修改list中的第二个元素
127.0.0.1:6379> LSET list 1 six
OK
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "six"
# 索引大于列表范围,发生错误
127.0.0.1:6379> LSET list 3 abc
(error) ERR index out of range
======================================================
# 分别向元素"six"的前后插入一个元素
127.0.0.1:6379> LINSERT list before six five
(integer) 3
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "five"
3) "six"
127.0.0.1:6379> LINSERT list after six seven
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "five"
3) "six"
4) "seven"
Lists总结:
- 实际上是一个链表,before Node after 的结构,left、right都可以插入元素
- 如果key不存在,将创建新的链表
- 如果key存在,根据命令往左或者往右插入元素
- 如果移除了所有值,空链表,那也就代表不存在了
- 因为是链表,所有在两边插入和修改,效率高,获取中间的元素,效率会低一些
使用场景:消息排队、消息队列(LPUSH RPOP)、栈(LPUSH LPOP)
4.Sets(集合)数据类型常用命令
set中的值不能有重复的,sets的所有命令都是以S开头的
命令 | 描述 |
---|---|
SADD | 将一个或者多个元素添加到指定集合中,如果key不存在,则先创建再添加 |
SMEMBERS | 返回一个指定集合中的所有元素 |
SISMEMBER | 判断一个集合中有没有指定的元素 |
SCARD | 返回集合中元素的数量,如果key不存在,则返回0 |
SRANDMEMBER | 随机从集合中抽取一个元素返回,可以设置count决定返回个数 |
SREM | 指定一个元素,将它从集合中移除 |
SPOP | 从集合移除并返回一个或多随机个元素 |
SMOVE | 将指定元素从集合A移动到集合B中 |
# 向myset集合中添加多个元素
127.0.0.1:6379> sadd myset a b c d
(integer) 4
# 返回myset集合中的所有元素
127.0.0.1:6379> smembers myset
1) "c"
2) "b"
3) "d"
4) "a"
# 返回myset中元素的个数
127.0.0.1:6379> scard myset
(integer) 4
# 判断myset集合里有没有a元素
127.0.0.1:6379> SISMEMBER myset a
(integer) 1
=====================================================
# 下面测试一下SRANDMEMBER命令的用法
# 先创建一个myset集合
127.0.0.1:6379> sadd myset a b c d
(integer) 4
127.0.0.1:6379> smembers myset
1) "c"
2) "b"
3) "d"
4) "a"
# 随机从myset集合中返回两个元素,count大于0并且小于元素的个数,返回count个随机元素
127.0.0.1:6379> SRANDMEMBER myset 2
1) "a"
2) "d"
# 返回myset中所有元素。count大于元素的个数,将集合所有元素返回
127.0.0.1:6379> SRANDMEMBER myset 6
1) "c"
2) "b"
3) "d"
4) "a"
# count小于0,返回的随机元素数量是count的绝对值的个数
127.0.0.1:6379> SRANDMEMBER myset -2
1) "d"
2) "c"
# count的绝对值大于元素的个数,则返回的结果集里会出现一个元素出现多次的情况.
127.0.0.1:6379> SRANDMEMBER myset -5
1) "b"
2) "c"
3) "d"
4) "c"
5) "a"
===================================================
# 从myset集合中随机移除一个元素
127.0.0.1:6379> spop myset
"d"
127.0.0.1:6379> smembers myset
1) "c"
2) "b"
3) "a"
# 从myset集合中移除指定元素,没有这个元素则不删除
127.0.0.1:6379> srem myset a bc
(integer) 1
127.0.0.1:6379> SMEMBERS myset
1) "c"
2) "b"
==================================================
# 清除一下数据库
127.0.0.1:6379> flushdb
OK
# 创建集合myset1和myset2
127.0.0.1:6379> sadd myset1 a b c d
(integer) 4
127.0.0.1:6379> sadd myset2 x y z
(integer) 3
# 将集合myset1中的b元素移动到myset2中
127.0.0.1:6379> smove myset1 myset2 b
(integer) 1
127.0.0.1:6379> smembers myset2
1) "y"
2) "b"
3) "z"
4) "x"
Sets还能操作交集、差集、并集
# 首先还是要创建两个集合用来测试
127.0.0.1:6379> sadd set1 a b c d
(integer) 4
127.0.0.1:6379> sadd set2 d c f x
(integer) 4
127.0.0.1:6379> sdiff set1 set2 #差集
1) "b"
2) "a"
127.0.0.1:6379> sinter set1 set2 # 交集
1) "c"
2) "d"
127.0.0.1:6379> sunion set1 set2 #并集
1) "c"
2) "a"
3) "b"
4) "f"
5) "x"
6) "d"
可以使用数学思想来使用Sets集合,QQ中的共同好友可以通过交集实现。
5.Hashs(哈希)数据类型常用命令
Redis是用key-value存储的,所以Hashs存储值的方式是key-map,进而演变成key-field-value。本质上与Strings类型没有太大区别,都是key-value
Hashs指令都是以H开头的。
命令 | 描述 |
---|---|
HSET | 设置 key 指定的哈希集中指定field 的value |
HGET | 获取key 指定的哈希集中指定field所关联的value |
HMSET | 设置 key 指定的哈希集中指定field的value ,可以同时设置多个field来获取多个value |
HMGET | 获取key 指定的哈希集中指定field所关联的value ,可以同时设置多个field来获取多个value |
HGETALL | 返回哈希集中所有的field和value |
HLEN | 获取哈希表中包含的field的数量 |
HEXISTS | 检查在哈希表中是否存在指定的field |
HVALS | 返回 哈希表中所有的field |
HKEYS | 返回 哈希表中所有的value |
HINCRBY | 增加哈希表中field对应的value的数值 |
HDEL | 将哈希表中的一个字段删除 |
# 创建一个hash,里面有字段field1、field2,有值abc、xyz
127.0.0.1:6379> hset hash field1 abc field2 xyz
(integer) 2
# 从hash中获取field1的值
127.0.0.1:6379> hget hash field1
"abc"
# 同时给user哈希表设置name、age字段,值为zhangsan、18
127.0.0.1:6379> hmset user name zhangsan age 18
OK
# 获取哈希表中name、age字段的值
127.0.0.1:6379> hmget user name age
1) "zhangsan"
2) "18"
# 获取user哈希表中的所有的字段和值
127.0.0.1:6379> HGETALL user
1) "name"
2) "zhangsan"
3) "age"
4) "18"
====================================================
# hash中有两个字段
127.0.0.1:6379> HLEN hash
(integer) 2
# hash中存在一个field1的字段
127.0.0.1:6379> hexists hash field1
(integer) 1
# 返回hash所有的字段
127.0.0.1:6379> HKEYS hash
1) "field1"
2) "field2"
# 返回hash所有的值
127.0.0.1:6379> HVALS hash
1) "abc"
2) "xyz"
==================================================
127.0.0.1:6379> hmset user name zhangsan age 18 sex man
OK
# 给name的自增1,因为name的值不是整型,将会报错
127.0.0.1:6379> HINCRBY user name 1
(error) ERR hash value is not an integer
# age的值是整型,自增1,返回自增后的值
127.0.0.1:6379> HINCRBY user age 1
(integer) 19
# 将sex字段删除
127.0.0.1:6379> hdel user sex
(integer) 1
127.0.0.1:6379> HGETALL user
1) "name"
2) "zhangsan"
3) "age"
4) "19"
相比较于Strings类型,Hashs更适合对象的存储,Strings适合字符存储
6.ZSets(有序集合)
在Sets的基础上增加了一个值,set k1 v1 -> zset k1 score v1 。
并且在有序集合里不允许存在重复的成员。
跟前面几种类型相似,所有的命令都是以Z开头
① ZADD key score member [score member …]
1.将指定成员添加到有序集合中去,添加时可以指定多个分数/成员(score/member)。
2.有序集合按照分数以递增的方式进行排序,并且不能存在重复的成员
② ZRANGE key start stop
从有序集合中返回指定范围内的元素,返回的元素按照从score从小到大排序
ZREVRANGE key start stop
从有序集合中返回指定范围内的元素,返回的元素按照从score从大到小排序
# 添加三个元素到myset中去
127.0.0.1:6379> zadd myset 1 one 2 two 3 three
(integer) 3
# 返回myset中所有的元素,withscores选项会将元素与score一起返回
127.0.0.1:6379> zrange myset 0 -1 withscores
1) "one"
2) "1"
3) "two"
4) "2"
5) "three"
6) "3"
③ ZRANGEBYSCORE key min max
1.设置一个区间,把在这个区间内的所有score的所有元素从有序集合中返回,返回的元素按从小到大排序
2.min和max可以设置为-inf和+inf ,表示负无穷大与正无穷大
3.区间默认是闭区间(小于等于或大于等于),可以通过在min或max前面设置一个 ( 符号来表示这是开区间(小于或大于)
ZREVRANGEBYSCORE key max min
1.与ZRANGEBYSCORE 类似,不过它是将元素从大到小排序
1.ZREVRANGEBYSCORE集合中按得分从高到底排序,所以"max"在前面,"min"在后面, ZRANGEBYSCORE集合中按得分从底到高排序,所以"min"在前面,"max"在后面。
# 设置一个工资表
127.0.0.1:6379> zadd salary 5000 zhangsan 2000 lisi 3000 wangwu
(integer) 3
# 返回工资在4000以内的名字(从小到大)
127.0.0.1:6379> ZRANGEBYSCORE salary -inf 4000
1) "lisi"
2) "wangwu"
# 返回2000到4000之间的名字,不包括2000(从小到大)
127.0.0.1:6379> ZRANGEBYSCORE salary (2000 4000
1) "wangwu"
# 将salary集合中所有元素从大到小排序返回
127.0.0.1:6379> ZREVRANGEBYSCORE salary +inf -inf withscores
1) "zhangsan"
2) "5000"
3) "wangwu"
4) "3000"
5) "lisi"
6) "2000"
④ ZREM key member
指定一个元素,将他从有序集合中移除
⑤ ZCARD key
返回有序集合中元素的个数
⑥ ZCOUNT key min max
设置一个区间,将在哪个区间内的元素个数返回
# 从salary中移除元素zhangsan
127.0.0.1:6379> ZREM salary lisi
(integer) 1
# 查看salary中所有元素个数
127.0.0.1:6379> ZCARD salary
(integer) 2
# 查看在salary中,score在1999到5000之间的元素个数
127.0.0.1:6379> ZCOUNT salary 1999 5000
(integer) 2
ZSets可以用于排行榜,普通消息、重要消息等场景。