一、非关系型数据库Nosql(不仅仅是sql)的四大分类:
1.KV键值对:
新浪:Redis
美团:Redis+Tair
阿里/百度:Redis+memecache
2.文档型数据库(bson 格式和jason一样)
MongoDB(一般必须要掌握)
MongoDB是一个基于分布式文件存储的数据库,C++存储,主要用来处理大量文档。
MongoDB是一个介于关系型数据库和非关系型数据库中中间的产品。
MongoDB是非关系型数据库功能最丰富,最像关系型数据库的。
3.列存储数据库
你现在学的MYSQL就是列存储数据库,但是他不是NoSQL
HBase
分布式文件系统
4.图关系数据库
他不是存图形,放的是关系,比如:朋友圈社交网络,广告推荐。
Neo4j,InfoGrid;只要公司需要你也要去学,你是一块砖,哪里需要哪里搬
二、Redis连接与退出
我用的宝塔安装的Redis,就不用配置了。
连接:
redis-cli -p 6379
shutdown 关闭redis
然后到未连接状态,直接exit退出即可
然后可以再次查看进程是否存在
ps -ef|grep redis
三、Redis的五大数据类型
String
set key1 v1 #添加
get key1 #获取key1的值
keys * #查看所有key
exists key1 #判断是否存在(1/0)
append key1 "hello" #追加字符串 如果key不存在,就相当于setkey
strlen key1 # 获取字符串长度
-----------------------------------------------------
set views 0 # 设置初始浏览量为0
incr views # 自增1
decr views # 自减1
INCRBY views 10 #【步长+增量】
DECRBY views 10 #【步长-增量】
-----------------------------------------------------
GETRANGE key1 0 3 # 截取字符串 [0,3]
GETRANGE key1 0 -1 # 读取全部的字符串 和 get key是一样的
setrange key2 1 xx # 替换指定位置开始的字符串!
-----------------------------------------------------
【setex】:(set with expire)# 设置过期时间
【setnx】:(set if not exist)# 不存在再设置(在分布式锁中会常常使用!)
setex key3 30 "hello" # 设置key3的值伟hello,30秒后过期
ttl key3 #查看剩余时间,key不存在时返回-2,key没设置时间返回-1
SETNX mykey "redis" # 如果mykey不存在,创建mykey
-----------------------------------------------------
mset k1 v1 k2 v2 k3 v3 # 同时设置多个值
mget k1 k2 k3 # 同时获取多个值
msetnx k1 v1 k4 v4 # msetnx 是一个原子性的操作 要么一起成功/一起失败!
-----------------------------------------------------
set article:{id}:views 0 # 设置文章编号为id的对象的初始浏览量,为0
List
在redis里面,我们可以把list玩成,栈、队列、阻塞队列!
一边进一边出:队列
一边进不能出:栈
两边都打开都能同时取:阻塞队列
Redis不区分大小写命令!
字符串加不加双引号都没事,会自动识别
LPUSH list one #将一个值或者多个值,插入到列表头部(左)
LRANGE list 0 -1 # 获取list中的值
LRANGE list 0 2 # 通过区间获取具体的值!(0,2)
rpush list right # 将一个值或者多个值,插入到列表尾部(右)
Lpop list # 从左边移除1ist的第一个元素
Rpop list # 从右边移除1ist的第一个元素
lindex list 1 # 通过下标 获取list中下标为1的元素
llen list # 返回列表的长度
LREM list 2 three # 移除list中的three 并且移除2个
【Ltrim】
trim 修剪操作, list:截断
LTRIM mylist 1 2 # 通过下标截取指定的长度,这个1ist已经被改变了,截断了只剩下截取的元素!
-----------------------------------------------------
【rpoplpush】 移除列表的最后一个元素,将他移动到新的列表中!
RPOPLPUSH mylist(旧) myotherlist(新列) # 移除列表的最后一个元素,将他移动到新的列表中!
-----------------------------------------------------
【lset】 将列表中指定下标的值替换为另外一个值,更新操作
EXISTS list # 判断列表是否存在
lset list 0 item # 如果不存在列表我们去更新就会报错||如果存在,更新当前下标的值
(error) ERR no such key
-----------------------------------------------------
【linsert】将某个具体的value插入到列中的某个元素的前面或者后面
LINSERT mylist before(after) "world" "other"
Set
所有的Set命令都是S开头的!
sadd myset "hello" # set集合中添加元素 注意set中的值不能重复的!
SMEMBERS myset # 查看指定set的所有值
SISMEMBER myset hello # 判断某一个值是不是在set集合中!
SCARD myset # 获取set集合中的内容元素个数!
srem myset hello # 移除set集合中的指定元素
-----------------------------------------------------
SRANDMEMBER myset # 随机抽选出一个元素
SRANDMEMBER myset 2 # 随机抽选出指定个数的元素
-----------------------------------------------------
spop myset # 随机删除key 附:栈的弹出函数pop()
smove myset myset2 kuangshen # 将一个指定的值,移动到另外一个set集合!
sdiff key1 key2 # 差集 注意是以key1为参照物
1) "b"
2) "a"
sinter key1 key2 # 交集 共同好友就可以这么实现
sunion key1 key2 # 并集
微博,A用户将所有关注的人放在一个set集合中!将它的粉丝也放在一个集合中!
共同关注,共同爱好,二度好友,推荐好友!(六度分割理论)
Hash(哈希)
你可以理解成map集合 key-value形式,只是这个value是一个map集合的形式
本质和String类型没有太大区别,还是一个简单的key-vlaue!
hset myhash field1 kuangshen # set 一个具体 key-value
hget myhash field1 # 获取1个字段值
hmset myhash field1 hello field2 world # set 多个具体 key-value 存在则覆盖
hkeys myhash # 只获取所有key
hvals myhash # 只获取所有value
hmget myhash field1 field2 # 获取多个字段值
hgetall myhash # 获取哈希中全部的数据key和value
hlen myhash # 获取哈希表字段的数量
hdel myhash field1 # 删除hash指定key字段:对应的value值也就消失了
hexists myhash field2 # 判断hash中指定字段是否存在!
hincrby myhash field3 1 # 设置自增1
hincrby myhash field3 -1 # 设置自减
hsetnx myhash field4 hello # 如果不存在field4则可以设置valus值为hello||如果存在则不能设置
Zset(有序集合)
zadd myset 1 one # 添加1个值
zrange myset 0 -1 # 遍历打印所有数据
ZRANGEBYSCORE salary -inf +inf # 显示全部用户 【从小到大】
ZREVRANGE salary 0 -1 # 【从大到小】 进行排序 rev反转的意思
ZRANGEBYSCORE salary -inf 2500 withscores # 显示工资小于2500的升序排列
zunionstore unkey12 2 k1 k2 #合并两个集合k1,k2
zrem salary xiaoming # 移除有序集合中的元素
zcard salary # 获取有序集合中的个数
zcount myset 1 3 # 获取指定区间的成员数量
三种特殊数据类型
geospatial 地理位置空间
官方网址:https://www.redis.net.cn/order/3689.html
朋友的定位,附近的人,打车距离计算?
Redis 的 Geo 在Redis3.2版本就推出了!这个功能可以推算地理位置的信息,两地之间的距离,方圆几里的人!
可以查询一些测试数据:https://jingweidu.51240.com/
# getadd 添加地理位置
# 规则:南北两级无法直接添加,我们一般会下载城市数据,直接通过java程序一次性导入!
# 参数 key 值(纬度、经度、名称)
# 有效的经度从-180度到180度。
# 有效的纬度从-85.05112878度到85.05112878度。
geoadd china:city 116.40 39.90 beijing
# geopos
geopos china:city hangzhou beijing # 获取指定的城市的经度 和 维度!
geodist 返回两个给定位置之间的距离
m 表示单位为米。
km 表示单位为千米。
mi 表示单位为英里。
ft 表示单位为英尺。
geodist china:city hangzhou beijing km
# georadius 以(给定的经纬度)为中心, 找出某一半径内的元素
GEORADIUS china:city 110 30 1000 km # 以110,30这个经纬度为中心,寻找方圆1000km内的城市
GEORADIUS china:city 110 30 500 km withdist # 显示到中间位置的直线距离 半径500km
GEORADIUS china:city 110 30 500 km withcoord # 显示到中心距离半径500km的城市 + 经纬度信息
GEORADIUS china:city 110 30 500 km withcoord withdist count 3 # 筛选出指定结果
GEORADIUSBYMEMBER
# 找出位于指定范围内的元素,中心点是由给定的位置元素决定
GEORADIUSBYMEMBER china:city beijing 1000 km
GEO 底层的实现原理:Zset! 我们可以用Zset命令来操作Geo
hyperloglog 位图
什么是基数?
基数(一个集合中不重复的元素)
统计疫情感染人数:存身份标识码
优点:占用的内存是固定的,2^64不同的元素的技术,只需要废12kb内存。如果要从内存角度来比较的话Hyperloglog首选!
如果允许容错,那么一定可以使用Hyperloglog
如果不允许容错,就使用 set 或 自己的数据类型 即可
pfadd mykey a b c d e f g h i j # 创建第一组元素 mykey
PFCOUNT mykey # 统计mykey元素的基数数量
PFMERGE mykey3 mykey mykey2 # 合并两组 mykey mykey2=>mykey3并集
bitmap 位图
面试题:如何筛选用户是最快的,0-1-0-1是最快的。
统计疫情感染人数:0 0 1 0 0
14亿个中国人,设14亿个0,被感染了设为1.
统计用户信息,活跃、不活跃。登录、未登录。打卡,钉钉打卡打卡!只要2个状态的,都可以用Bitmaps来处理。
userid status day 这样非常麻烦
Bitmaps位图,数据结构!都是操作二进制位来进行记录,就只有0和1两个状态!
365天=365bit 1字节=8bit 46个字节左右!
【getbit、setbit】
setbit sign 3 1 # 输入某一天是否打卡
setbit sign 2 0
getbit sign 6 # 查看某一天是否打卡
【bigcount】
bitcount sign # 查看是否全勤 统计操作,统计打卡的天数
事务
原子性:要么同时成功,要么同时失败。
redis单条命令是保障原子性的, 但是事务是不保证原子性的
Redis事务本质:一组命令的集合!一个事务中的所有命令都会被序列化,在事务执行过程的中,会按照顺序执行!
- 一次性执行
- 顺序性
- 排他性
不允许别人感染
------ 队列 set set set 执行 ------
Redis事务没有隔离级别的概念
所有的命令在事务中,并没有直接被执行!
在队列中并没有执行
只有发起执行命令的时候才会执行!Exec
redis的事务:
- 开启事务(multi)
- 命令入队(…)
- 执行事务(exec)
multi # 开启事务
set k1 v1 语句
.
.
DISCARD # 取消事务
exec # 执行事务
编译型异常(代码有问题!命令有错!),事务中所有的命令都不会被执行
运行时异常(1/0),如果事务队列中存在语法性,那么执行命令的时候,其他命令是可以正常执行的 错误命令抛出异常
redis还可以做监控
监控!Watch监视器
悲观锁:
很悲观,认为什么时候都会出问题,无论做什么都会加锁!
乐观锁:
很乐观,认为什么时候都不会出问题,所以不会上锁!
更新的时候去判断一下,在此期间是否有人修改过这个数据,mysql中的version字段!
- 获取version
- 更新的时候比较version
我们基本大部分使用乐观锁为主,很少使用悲观锁,因为效率太低了
node1:6379> set money 100
OK
node1:6379> set out 0
OK
node1:6379> watch money # 监视money
OK
node1:6379> MULTI
OK
node1:6379> DECRBY money 10
QUEUED
node1:6379> INCRBY out 10
QUEUED
############## 另一线程修改数据 ##########
node1:6379> set money 1000
OK
############## 原线程执行 ##########
node1:6379> exec # 执行之前,另外线程修改了我们的值,就会导致执行失败
(nil)
############# 还想继续执行怎么办? #############
node1:6379> unwatch # 先解锁
OK
node1:6379> WATCH money # 重新加锁,获取最新version 再操作即可
OK
node1:6379> exec # 对比监视的值是否发生了变化,如果没有变化,那么可以执行成功,如果变了就执行失败