1.Redis入门
Redis入门
redis 数据类型
redis的数据类型一共有 8种 分别是 5 种基本数据类型和 3 种特殊数据类型
基本数据类型 :
- String 字符串
- string类型是Redis最基本的数据类型,一个键最大能存储512MB。
- Hash 哈希
- hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。
- List 列表
- Set 集合
- 该普通Set集合是无序且唯一的
- ZSet 有序集合
- 该Set添加时需要多添加一个score数值来进行排序 该数值可以重复,但是元素还是唯一的
特殊数据类型:
- Bitmap
- HyperLogLog
- geo
基础入门
在不修改配置文件的情况下,redis默认提供16个数据库 下标为0-15
基础命令
切换数据库命令: select 下标
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]>
清空当前数据库的数据:flushdb
127.0.0.1:6379[1]> set name xf
OK
127.0.0.1:6379[1]> get name
"xf"
127.0.0.1:6379[1]> flushdb
OK
127.0.0.1:6379[1]> get name
(nil)
清空所有数据库的数据:flushall
127.0.0.1:6379[1]> get name
"xf"
127.0.0.1:6379[1]> select 0
OK
127.0.0.1:6379> flushall
OK
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> get name
(nil)
获取某个键是否存在:exists {key}
127.0.0.1:6379> exists name
(integer) 0
127.0.0.1:6379> set name xf
OK
127.0.0.1:6379> exists name
(integer) 1
#后面可以跟多个key 返回的数值就是有多少个key是存在的
127.0.0.1:6379> exists name name1
(integer) 1
127.0.0.1:6379>
移动某个键值对到其他数据库:move {key} {db}
127.0.0.1:6379> keys *
1) "name"
127.0.0.1:6379> move name 1
(integer) 1
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> get name
"xf"
127.0.0.1:6379[1]>
设置某个键值对的过期时间:expire {key} {seconds}
127.0.0.1:6379> get name
"xf_1"
127.0.0.1:6379> expire name 1
(integer) 1
127.0.0.1:6379> get name
(nil)
# 过期后这个值就被删除了
127.0.0.1:6379>
获得某个键值对将要到期的时间(单位:秒):ttl {key}
127.0.0.1:6379> get name
"xf_10"
127.0.0.1:6379> expire name 10
(integer) 1
# ttl 返回的数值就是要到期的秒数
127.0.0.1:6379> ttl name
(integer) 9
127.0.0.1:6379> ttl name
(integer) 8
127.0.0.1:6379> ttl name
(integer) 7
127.0.0.1:6379> ttl name
(integer) -2
127.0.0.1:6379> ttl name
(integer) -2
# 到期后被删除
127.0.0.1:6379> get name
(nil)
127.0.0.1:6379>
查看某个值的类型:type {key}
127.0.0.1:6379> get name
"xf"
127.0.0.1:6379> type name
string
127.0.0.1:6379>
基础概念
Redis在4.0以前是单线程的
-
为什么使用单线程?
-
redis是基于内存进行操作的,cpu的性能并不是redis的瓶颈,而线程解决的问题是cpu的使用效率,所以多线程对redis的提升并不算大,线程切换的时候反而会影响redis
-
多线程要考虑到线程安全等因素,所以会需要加入锁,但是加锁解锁也会影响其性能,甚至可能会出现死锁情况,所以使用的是单线程
-
-
Redis为什么单线程还这么快
- 误区1:高性能服务器一定是多线程的?
- 误区2:多线程一定比单线程快?
- 在多线程中,CPU会对多个上下文进行切换,切换也有一定的时间。
-
核心
- redis将全部数据是放在了内存(RAM)中的,所以说使用单线程是最高效的。
Redis可以干什么?
- Redis是一个基于内存的 数据结构存储系统 它可以作用于:
- 数据库
- 缓存
- 消息中间件
五大基本数据类型
String (字符串)
-
append {key} {value} 追加字符串
127.0.0.1:6379> get name "xf" # 返回的是追加后的字符串长度 127.0.0.1:6379> append name 123 (integer) 5 # 追加后字符串 127.0.0.1:6379> get name "xf123"
-
如果当前 {key} 不存在 就相当于
set {key}
-
-
strlen {key} 获取字符串长度
# 获取当前字符串长度 127.0.0.1:6379> strlen name (integer) 5 127.0.0.1:6379> get name "xf123"
-
incr {key} 自增1
-
incyby {key} step 自增自定义步长
-
-
decr {key} 自减1
-
decrby {key} step 自减自定义步长
-
-
getrange {key} {start} {end} 截取(包括) {start} 到 {end} 的字符串
127.0.0.1:6379> get name "xf123" #0123 127.0.0.1:6379> getrange name 0 3 "xf12" 127.0.0.1:6379> getrange name 0 -1 # -1是查看全部的字符串 "xf123" 127.0.0.1:6379>
-
setrange {key} {index} {text} 将值下标为 {index} 的字符替换成 {text}
- 替换长度根据 {text} 长度决定
127.0.0.1:6379> get name "xf123" 127.0.0.1:6379> setrange name 1 ff (integer) 5 127.0.0.1:6379> get name "xff23" 127.0.0.1:6379>
-
setex {key} {second} {value} 设置值并设置过期时间
- 等价于
set {key} {value}
与expire {key} {second}
同时输入
127.0.0.1:6379> setex name 10 xf OK 127.0.0.1:6379> ttl name (integer) 8 127.0.0.1:6379> ttl name (integer) 7 127.0.0.1:6379>
- 等价于
-
setnx {key} {value} 如果当前{key}不存在 则设置为 {value} 存在则不变
- 分布式锁中常常使用
127.0.0.1:6379> get name (nil) 127.0.0.1:6379> setnx name xf (integer) 1 127.0.0.1:6379> get name "xf" 127.0.0.1:6379> setnx name xufan (integer) 0 127.0.0.1:6379> get name "xf" 127.0.0.1:6379>
-
mset {key} {value} [key value ...] 可以一次性设置多个值
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 OK 127.0.0.1:6379> keys * 1) "k3" 2) "k2" 3) "k1" 127.0.0.1:6379>
-
mget {key} [key key ...] 可以一次性获取多个字(按顺序获取)
127.0.0.1:6379> mget k1 k2 k3 1) "v1" 2) "v2" 3) "v3" 127.0.0.1:6379> mget k2 k1 k3 1) "v2" 2) "v1" 3) "v3" 127.0.0.1:6379>
-
msetnx 同上
setnx
命令 多个一块设置- 但是
msetnx
是原子性操作: 要么都成功 要么都失败 无关参数先后
127.0.0.1:6379> keys * 1) "k3" 2) "k2" 3) "k1" 127.0.0.1:6379> msetnx k4 v4 k1 v1 (integer) 0 127.0.0.1:6379> keys * 1) "k3" 2) "k2" 3) "k1" 127.0.0.1:6379>
- 但是
-
getset {key} {value} 该命令先获取值后立马更新值
127.0.0.1:6379> get user:1 "{name:zhangsan,age:10}" 127.0.0.1:6379> getset user:1 xf "{name:zhangsan,age:10}" 127.0.0.1:6379> get user:1 "xf" 127.0.0.1:6379>
小技巧
string类型来存储字符串可以使用json格式 也可以用一种很巧妙的形式
如将他的一些json中的key再放入 key中
-
# json方式 127.0.0.1:6379> set user:1 {name:zhangsan,age:10} OK 127.0.0.1:6379> get user:1 "{name:zhangsan,age:10}" 127.0.0.1:6379> # other 127.0.0.1:6379> mset user:1:name zhangsan user:1:age 10 OK 127.0.0.1:6379> mget user:1:name user:1:age 1) "zhangsan" 2) "10" 127.0.0.1:6379>
可以将他的属性名也存入在 key 中 有点类似mysql中的联合主键吧
List (列表)
-
lpush {key} {value} 从左边添加一个新元素至{key} 该列表内
-
rpush {key} {value} 从右边 同上
127.0.0.1:6379> lpush list v1 (integer) 1 127.0.0.1:6379> LRANGE list 0 -1 1) "v1" 127.0.0.1:6379>
-
lpop {key} 移除并获取左边第一个元素
-
rpop {key} 从右边 同上
127.0.0.1:6379> LRANGE list 0 -1 1) "v2" 2) "v1" 127.0.0.1:6379> lpop list "v2" 127.0.0.1:6379> LRANGE list 0 -1 1) "v1" 127.0.0.1:6379>
-
lrange {key} {start_index} {end_index} 列表范围内的元素
- lrange {key} 0 -1 则为获取 {key} 该列表的所有元素
127.0.0.1:6379> LRANGE list 0 -1 1) "v1" 127.0.0.1:6379>
-
lindex {key} {index} 获取 {key} 该列表中下标为 {index} 的元素
127.0.0.1:6379> LRANGE list 0 -1 1) "v1" # index:0 2) "v2" # index:1 3) "v3" # index:2 127.0.0.1:6379> LINDEX list 1 "v2" 127.0.0.1:6379>
-
llen {key} 获取列表长度
127.0.0.1:6379> LRANGE list 0 -1 1) "v1" 2) "v2" 3) "v3" 127.0.0.1:6379> llen list (integer) 3 127.0.0.1:6379>
-
lrem {key} {count} {element} 删除列表中 {count} 个 值为 {element} 的元素
127.0.0.1:6379> LRANGE list 0 -1 1) "v2" 2) "v2.5" 127.0.0.1:6379> lrem list 1 v2 (integer) 1 127.0.0.1:6379> LRANGE list 0 -1 1) "v2.5" 127.0.0.1:6379>
-
Linsert {key} {before|after} {text} {insert_text}
- 往 {key} 列表中的 {text} 元素之前 {before} 或之后 {after} 插入 {insert_text}
127.0.0.1:6379> LINSERT list after v2 v2.5 (integer) 5 127.0.0.1:6379> LRANGE list 0 -1 1) "v1" 2) "v2" 3) "v2.5" 4) "v3" 5) "v4" 127.0.0.1:6379>
-
rpoplpush {原key} {新key} 将 原列表 中的最右边元素移至 新列表 的左边
- 等价于 rpop {key} + lpush {key} {value}
127.0.0.1:6379> LRANGE list 0 -1 1) "v1" 2) "v2" 3) "v2.5" 4) "v3" 5) "v4" 127.0.0.1:6379> RPOPLPUSH list list_new "v4" 127.0.0.1:6379> LRANGE list 0 -1 1) "v1" 2) "v2" 3) "v2.5" 4) "v3" 127.0.0.1:6379> LRANGE list_new 0 -1 1) "v4"
-
ltrim {key} {start} {end} 修剪 {key} 列表,只保留 [start,end] 中的元素 ,其他元素舍弃
127.0.0.1:6379> LRANGE list 0 -1 1) "v1" # index:0 2) "v2" # index:1 3) "v2.5" # index:2 4) "v3" # index:3 127.0.0.1:6379> LTRIM list 1 2 OK 127.0.0.1:6379> LRANGE list 0 -1 1) "v2" 2) "v2.5" 127.0.0.1:6379>
Set (集合)
Set中的值是不能重复且无序的!
-
sadd {key} {value} 往 {key} 中添加 {value} 值
127.0.0.1:6379> sadd set s1 (integer) 1 127.0.0.1:6379> SMEMBERS set 1) "s1" 127.0.0.1:6379>
-
smembers {key} 查看指定 {key}
127.0.0.1:6379> SMEMBERS set 1) "s1" 127.0.0.1:6379>
-
sismember {key} {value} 判断 {key} 中是否存在 {value}
127.0.0.1:6379> SMEMBERS set 1) "s1" 127.0.0.1:6379> SISMEMBER set s1 # 存在返回1 (integer) 1 127.0.0.1:6379> SISMEMBER set s2 # 不存在返回0 (integer) 0 127.0.0.1:6379>
-
scard {key} 获取 {key} 中元素个数
- 类似llen {key}
127.0.0.1:6379> SCARD set (integer) 1 127.0.0.1:6379> SMEMBERS set 1) "s1" 127.0.0.1:6379>
-
srem {key} {member} [members ...] 在 {key} 中移除单个或多个 {member} 元素
127.0.0.1:6379> SMEMBERS set 1) "s1" 2) "s" 3) "s2" 4) "s3" 127.0.0.1:6379> SREM set s (integer) 1 127.0.0.1:6379> SMEMBERS set 1) "s1" 2) "s2" 3) "s3" 127.0.0.1:6379>
-
srandmember {key} [count] 在集合 {key} 中抽取 [count] 个随机元素
- count默认为1
127.0.0.1:6379> SRANDMEMBER set "s3" 127.0.0.1:6379> SRANDMEMBER set "s2" 127.0.0.1:6379> SRANDMEMBER set "s2" 127.0.0.1:6379> SRANDMEMBER set "s2" 127.0.0.1:6379>
-
spop {key} [count] 弹出 {key} 中随机选取的一个元素
127.0.0.1:6379> spop set "s2" 127.0.0.1:6379> SMEMBERS set 1) "s1" 2) "s3" 127.0.0.1:6379>
-
smove {key} {new_key} {source} 将 {key} 中的 {source} 移动到 {new_key} 中
127.0.0.1:6379> smove set set_new s1 (integer) 1 127.0.0.1:6379> SMEMBERS set 1) "s3" 127.0.0.1:6379> SMEMBERS set_new 1) "s1" 127.0.0.1:6379>
集合运算
-
sinter {key} [keys ...] 交集运算
- 交集是两个集合中都拥有的元素的新集合 如a:{1,2,3} b:{2,3,4} 那么他们的交集就是{2,3}
127.0.0.1:6379> SMEMBERS set1 1) "1" 2) "2" 3) "3" 4) "4" 127.0.0.1:6379> SMEMBERS set2 1) "2" 2) "3" 3) "5" 127.0.0.1:6379> SINTER set1 set2 1) "2" 2) "3" 127.0.0.1:6379>
-
sunion {key} [keys...] 并集运算
- 并集将两个集合合并,去除重复项,包含了俩个集合所有的元素
127.0.0.1:6379> SMEMBERS set1 1) "1" 2) "2" 3) "3" 4) "4" 127.0.0.1:6379> SMEMBERS set2 1) "2" 2) "3" 3) "5" 127.0.0.1:6379> SUNION set1 set2 1) "1" 2) "2" 3) "3" 4) "4" 5) "5" 127.0.0.1:6379>
-
sdiff {key} [keys...] 差集运算
- 差集是在 {key} 集合中有 而 [keys] 集合中没有的元素
127.0.0.1:6379> SDIff set1 set2 1) "1" 2) "4" 127.0.0.1:6379>
Zset (有序集合)
zset是一种特殊的set类型 他相较于set类型的区别是有序的,但是也是不重复元素的类型
-
zadd {key} {score} {member} 添加新元素和{score}至{key}
127.0.0.1:6379> zadd zset 1 one 2 two 3 three (integer) 3 127.0.0.1:6379> ZRANGE zset 0 -1 1) "one" 2) "two" 3) "three" 127.0.0.1:6379>
-
zrange {key} {start} {end} 展示[start,end]的数据 同上list使用一样
- zrange {key} 0 -1 为展示{key}中的全部数据
127.0.0.1:6379> ZRANGE zset 0 -1 1) "one" 2) "two" 3) "three" 127.0.0.1:6379>
-
zrem {key} {member} 删除{key}中的指定元素
127.0.0.1:6379> ZREM zset three (integer) 1 127.0.0.1:6379> ZRANGE zset 0 -1 1) "one" 2) "two" 127.0.0.1:6379>
-
zcard {key} 获取{key}的集合长度
127.0.0.1:6379> ZCARD zset (integer) 2 127.0.0.1:6379>
-
zrangebyscore {key} {min} {max} [withscores] 取score在[min,max]范围内的所有元素并排序
- 该命令为升序,如果改为降序需要使用
zrevrangebyscore
命令 - {min}和{max} 可以用 -inf +inf 来代替
- [withscores] 参数是是否需要显示元素的score值
# 升序 127.0.0.1:6379> ZRANGEBYSCORE zset -inf +inf 1) "one" 2) "two" # 降序 127.0.0.1:6379> ZrevRANGEBYSCORE zset +inf -inf 1) "two" 2) "one" 127.0.0.1:6379>
- 该命令为升序,如果改为降序需要使用
-
zcount {key} {min} {max} 获取{key}中score 在范围[min,max]中的成员数量
127.0.0.1:6379> ZRANGE zset 0 -1 1) "one" 2) "two" 3) "three" 4) "four" 127.0.0.1:6379> ZCOUNT zset 1 3 (integer) 3 127.0.0.1:6379>
该集合通常用于排名、排行榜之类的需要一定顺序和权重来排序,但是元素唯一的情况。
三种特殊数据类型
- Geo 地理位置
- 标记经纬度后可以计算距离
- 两点之间距离
- 方圆距离
- 通常用在附近的人 、需要涉及距离等参数
- 标记经纬度后可以计算距离
- Hyperloglog 基数统计
- 类似于set 也是不重复的集合
- 优势:可以存放 2^64 个元素 且内存使用极小,固定只有 12kb
- 劣势:有一定错误率,官方表示约:**0.81% **错误
- 一般是用于统计浏览量、播放量等需要筛选唯一值且可以接受一定错误情况下使用
- 类似于set 也是不重复的集合
- Bitmaps 位存储
- 只有 0 和 1 状态表示 可以用于只有俩种状态的情况 类似以下场景
- 登录状态(已登录、未登录)
- 打卡签到情况(签到、缺勤)
- 只有 0 和 1 状态表示 可以用于只有俩种状态的情况 类似以下场景