NoSQL(NoSQL = Not Only SQL ),意即“不仅仅是SQL”,泛指非关系型的数据库。
NoSQL 不依赖业务逻辑方式存储,而以简单的key-value模式存储。因此大大的增加了数据库的扩展能力。
多路复用是指使用一个线程来检查多个文件描述符(Socket)的就绪状态,比如调用select和poll函数,传入多个文件描述符,如果有一个文件描述符就绪,则返回,否则阻塞直到超时。得到就绪状态后进行真正的操作可以在同一个线程里执行,也可以启动线程执行(比如使用线程池)
串行 vs 多线程+锁(memcached) vs 单线程+多路IO复用(Redis)
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> set name wht
OK
127.0.0.1:6379> get name
"wht"
127.0.0.1:6379>
redis一共有16个数据库,默认使用第一个数据库 ,可以使用select来切换数据库
[root@VM-12-7-centos ~]# redis-cli
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> dbsize
(integer) 0
插入key值
127.0.0.1:6379> set name wht
OK
查看当前所有key值
127.0.0.1:6379> keys *
1) "name"
查看key值内容
127.0.0.1:6379> set name wht
OK
127.0.0.1:6379> get name
"wht"
删除某个key值 mov +key值+当前数据库
127.0.0.1:6379> move name 1
(integer) 1
给某个key值加上过期时间和查看剩余时间
127.0.0.1:6379> set name wht
OK
127.0.0.1:6379> expire name 10
(integer) 1
127.0.0.1:6379> ttl name
(integer) 7
127.0.0.1:6379> ttl name
(integer) 1
127.0.0.1:6379
查看当前key的类型
127.0.0.1:6379> keys *
1) "age"
2) "name"
127.0.0.1:6379> type age
string
127.0.0.1:6379> type name
string
清空当库的全部key值
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> keys *
(empty array)
清除所有数据库
flushall
查看当前key值是否存在
exists name
Redis是单线程
Redis是基于内存操作的,CPU并不是Redis的性能瓶颈,主要由机器内存和网络带宽决定
Redis所示c语言写的,官方数据,100000+QPS
核心:Redis将所有数据都放在内存中,所以使用单线程去操作是效率最高的
多线程上下文切换是个耗时的操作
给key值追加字段 append
127.0.0.1:6379> set name wht
OK
127.0.0.1:6379> append name wht2
(integer) 7
查看当前key值得长度
127.0.0.1:6379> get name
"whtwht2"
127.0.0.1:6379> STRLEN name
(integer) 7
加一减一操作
127.0.0.1:6379> get view
"0"
127.0.0.1:6379> incr view
(integer) 1
127.0.0.1:6379> get view
"1"
127.0.0.1:6379> decr view
(integer) 0
127.0.0.1:6379> get view
"0"
连续增加和连续减少
127.0.0.1:6379> get view
"0"
127.0.0.1:6379> INCRBY view 10
(integer) 10
127.0.0.1:6379> DECRBY view 5
(integer) 5
获取某个区间的字符(如果是0到-1表示获取全部字符串)
127.0.0.1:6379> get name
"whttttttt"
127.0.0.1:6379> GETRANGE name 0 3
"whtt"
setex(set with expire) 设置key3的值为hello 30秒后过期
127.0.0.1:6379> setex key3 30 "hello"
OK
127.0.0.1:6379> ttl key3
(integer) 21
setnx (set if not exist) 不存在则设置,在分布式锁中常用
127.0.0.1:6379> setnx name "wht2"
(integer) 0
127.0.0.1:6379> get name
"whttttttt"#还是原来的值,因为已经存在,所以创建失败
mset 批量创建
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3
OK
127.0.0.1:6379> keys *
1) "k2"
2) "k1"
3) "k3"
mget 批量获取
127.0.0.1:6379> mget k1 k2 k3
1) "v1"
2) "v2"
3) "v3"
msetnx 如果不存在则批量创建(遵循原子性原则)
127.0.0.1:6379> msetnx k1 v1 k2 v2 k4 v4
(integer) 0
127.0.0.1:6379> keys *
1) "k2"
2) "k1"
3) "k3 #因为k1 和k2存在,所以k4没有创建成功
设置一个json字符串保存数据
set user1:1{name:zhangsan,age:3}
127.0.0.1:6379> get user1:1
"{name:zhangsan,age:3}"
user:{id}:{filed}
127.0.0.1:6379> mset user2:1:name wht user2:1:age 18
OK
127.0.0.1:6379> mget user2:1:name user2:1:age
1) "wht"
2) "18"
getset 先get再set,如果不存在则创建,返回的是当前get的值
127.0.0.1:6379> GETSET db redis
(nil)
127.0.0.1:6379> get db
"redis"
字符串时应用场景最多的地方,不仅可以是字符串,还可以是数字
所有list命令都是l开头的
LPUSH LRANGE list作为堆栈使用,先进后出
127.0.0.1:6379> LPUSH list one
(integer) 1
127.0.0.1:6379> LPUSH list two
(integer) 2
127.0.0.1:6379> LPUSH list three
(integer) 3
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
RPUSH LPUSH list作为队列使用,可以从左边或者右边插入
127.0.0.1:6379> RPUSH list right
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
4) "right"
127.0.0.1:6379> LPUSH list left
(integer) 5
127.0.0.1:6379> LRANGE list 0 -1
1) "left"
2) "three"
3) "two"
4) "one"
5) "right"
LPOP RPOP 出栈
127.0.0.1:6379> LPOP list
"left"
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
4) "right"
LINDEX 通过索引获取元素
127.0.0.1:6379> LINDEX list 0
"three"
LLEN获取list长度
127.0.0.1:6379> LLEN list
(integer) 4
LREM 移除指定元素,可以指定数量
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "three"
3) "two"
4) "right"
127.0.0.1:6379> LREM list 2 three
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "right"
ltrim 截取指定list
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "three"
3) "two"
4) "right"
127.0.0.1:6379> ltrim list 1 2
OK
127.0.0.1:6379> LRANGE list 0 -1 #list已经被改变了
1) "three"
2) "two"
RPOPLPUSH 移除列表最后一个元素,移入新的lsit
127.0.0.1:6379> RPOPLPUSH list newlist
"two"
127.0.0.1:6379> LRANGE newlist 0 -1
1) "two"
LINSERT +before 和after 在指定字段后面或者前面插入新的值
127.0.0.1:6379> LINSERT list before "three" new
(integer) 2
127.0.0.1:6379> LINSERT list after three new2
(integer) 3
127.0.0.1:6379> LRANGE list 0 -1
1) "new"
2) "three"
3) "new2"
使用场景 :消息队列,栈
set集合的命令都是以s开头的
集合是不能重复的,且无序
插入sadd 和查询smembers
127.0.0.1:6379> sadd myset hello
(integer) 1
127.0.0.1:6379> sadd myset wht
(integer) 1
127.0.0.1:6379> sadd myset wht2
(integer) 1
127.0.0.1:6379> smembers myset
1) "wht"
2) "hello"
3) "wht2"
sismember判断某一个元素是不是在集合中’
sismember myset wht
scard 查看当前集合中有多少个元素
127.0.0.1:6379> SCARD myset
(integer) 3
srem(remove)从当前集合中移除某个元素
127.0.0.1:6379> SREM myset hello
(integer) 1
srandmember随机抽取一个集合的元素(类似抽奖)
127.0.0.1:6379> srandmember myset
"wht2"
127.0.0.1:6379> srandmember myset
"wht"
spop 随机删除一个集合中的元素
spop myset
smove将制定元素移动到另外一个集合中
127.0.0.1:6379> smove myset myset2 wht7
(integer) 1
127.0.0.1:6379> smembers myset2
1) "bbb"
2) "aaa"
3) "wht7"
sdiff求差集 sinter求交集 sunion求并集
127.0.0.1:6379> smembers myset2
1) "bbb"
2) "aaa"
3) "wht7"
127.0.0.1:6379> smembers myset
1) "wht8"
2) "aaa"
127.0.0.1:6379> SDIFF myset myset2
1) "wht8"
127.0.0.1:6379> sinter myset myset2
1) "aaa"
127.0.0.1:6379> SUNION myset myset2
1) "bbb"
2) "wht8"
3) "aaa"
4) "wht7"
交集可以做共同好友,共同关注,可能认识的人等功能
Map集合,key-value集合,这时候是map集合
所有hash命令都已h开头!
hset 加入值 ,hget取值
127.0.0.1:6379> hset myhash field1 wht1
(integer) 1
127.0.0.1:6379> hget myhash field1
"wht1"
hmset加入多个值, mget获取多个值, hgetall获取所有数据
127.0.0.1:6379> hmset myhash field1 hello1 field2 hello2
OK
127.0.0.1:6379> hmget myhash field1 field2
1) "wht1"
2) "hello2"
127.0.0.1:6379> hgetall myhash
1) "field1"
2) "hello1"
5) "field2"
6) "hello2"
设置值若有重复值则会覆盖原来的值
hdel删除指定的key字段
hdel myhash filed1
hlen获取hash表的字段长度
127.0.0.1:6379> hlen myhash
(integer) 2
exists当前键是否存在
127.0.0.1:6379> exists myhash field1
(integer) 1
hinceby给指定值增加指定值
127.0.0.1:6379> hset myhash field3 5
(integer) 1
127.0.0.1:6379> hincrby myhash field3 2
(integer) 7
hsetnx 如果不存在则创建,否则创建失败
设置键值对的方式
127.0.0.1:6379> hset user:1 name wht
(integer) 1
127.0.0.1:6379> hget user:1 name
"wht"
zadd添加 ,zrange 查询
127.0.0.1:6379> zadd myset 1 one
(integer) 1
127.0.0.1:6379> zadd myset 2 two 3 three
(integer) 2
127.0.0.1:6379> zrange myset 0 -1
1) "one"
2) "two"
3) "three"
zrangebyscore按照score从小到大排序
127.0.0.1:6379> zrangebyscore myset -inf +inf withscores
1) "one"
2) "1"
3) "two"
4) "2"
5) "three"
6) "3"
ZREVRANGEBYSCORE按照score从大到小排序
127.0.0.1:6379> ZREVRANGEBYSCORE myset +inf -inf
1) "three"
2) "two"
zrevrange按照索引从大到小排序 反之rerange是按照索引从小到大排序
127.0.0.1:6379> zrevrange myset 0 -1
1) "three"
2) "two"
zrem移除某个元素
zrem myset one
zcard获取有序集合中的个数
zcount获取某个区间的个数
127.0.0.1:6379> ZCOUNT myset 2 3
(integer) 2
应用场景:排行榜,班级排序
在redis3.2中支持推出地理位置功能,根据经度和纬度
geoadd添加地理位置
GEOADD china:city 116.40 39.90 beijing
GEOADD china:city 121.47 31.23 shanghai
geopos获取地理位置
127.0.0.1:6379> geopos china:city beijing shanghai
1) 1) "116.39999896287918091"
2) "39.90000009167092543"
2) 1) "121.47000163793563843"
2) "31.22999903975783553"
geodist获取两个位置的距离,单位默认是米,可以在最后指定单位
127.0.0.1:6379> geodist china:city beijing shanghai
"1067378.7564"
127.0.0.1:6379> geodist china:city beijing shanghai km
"1067.3788"
georadius以给定值为半径,在圆圈内寻找
127.0.0.1:6379> georadius china:city 110 40 1000 km
1) "beijing"
功能:附近的人
georadiusbymember以城市为圆心
127.0.0.1:6379> georadiusbymember china:city beijing 1000 km
1) "beijing"
基数就是不重复元素的个数,比如网站的访问人数,一个人访问一个网站多次是记作一次的
会有一定的错误率但在可接受范围内
pfadd增加 pfcount计算基数个数
127.0.0.1:6379> pfadd mykey a b c d e f
(integer) 1
127.0.0.1:6379> pfadd mykey2 a b c d e f g
(integer) 1
127.0.0.1:6379> pfcount mykey mykey2
(integer) 7
如果允许容错,则可以使用hyperloglog,否则应该使用集合
位存储 占用内存较少
用途:统计用户活跃度,打卡
setbit 设置状态 bitcount查询1的个数
127.0.0.1:6379> setbit sign 0 1
(integer) 0
127.0.0.1:6379> setbit sign 1 0
(integer) 0
127.0.0.1:6379> setbit sign 2 1
(integer) 0
127.0.0.1:6379> bitcount sign
(integer) 2
redis单条命令是符合原子性的
但redis的事务是没有原子性和隔离级别的
所有命令并没有直接被执行,而是发起执行命令时才会被执行
redis事务
multi开启事务,exec执行队列
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)> get k2
QUEUED
127.0.0.1:6379(TX)> EXEC
1) OK
2) OK
3) "v1"
4) "v2"
discard放弃事务,队列里的命令并不会执行
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> DISCARD
OK
127.0.0.1:6379> get k3
(nil)
事务错误类型
编译型异常 ,代码或命令有问题,事务中的所有命令都不会执行
运行时出现异常,事务队列中存在语法异常,执行命令时,其他命令可以正常执行,错误命令抛出异常
悲观锁:认为什么时候都会出问题,无论做什么都会加锁,影响性能
乐观锁:认为不会出问题,所以不会加锁,更新数据的时候去判断一下,在此期间是否有人修改过这个数据
watch可以开启监视对象