文章目录
1、NoSQL 分类
1.1、KV键值对
Redis
1.2文档型数据库(bson)
MongoDB:分布式文件存储数据库,主要存储文档
1.3、列存储数据库
HBase
分布式文件系统
1.4图关系数据库
Neo4j
2、Redis概述
Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步
redis:
1.内存存储,持久化(rdb、aof)
2.效率高,可以用于高速缓存
3.发布订阅系统
4.地图信息分析
5.计时器、计数器(浏览数)
3、redis-benchmark
自带的测试工具
redis-benchmark -h localhost -p 6379 -c 10 -n 10000
4、基本知识
默认16个数据库
select 0 #切换数据库
默认用DBSIZE查看大小
keys * #查看key值
127.0.0.1:6379> select 3 #切换数据库
OK
127.0.0.1:6379[3]> DBSIZE #查看DB大小
(integer) 0
127.0.0.1:6379[3]>
flushdb
flushall
redis是单线程
redis是基于内存操作,CPU不是瓶颈,所以是内存和网络带宽是瓶颈,既然是可以使用单线程就可以使用单线程。
不用切换线程,造成CPU资源的浪费
读写在内存中,不用进行IO操作
5、数据类型
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件MQ。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
127.0.0.1:6379> set name mistyzcc
OK
127.0.0.1:6379> set age 1
OK
127.0.0.1:6379> keys *
1) "name"
2) "age"
127.0.0.1:6379> exists name
(integer) 1
127.0.0.1:6379> move name 1
(integer) 1
127.0.0.1:6379> exists name
(integer) 0
127.0.0.1:6379>
127.0.0.1:6379> keys *
1) "name"
2) "age"
127.0.0.1:6379> get name
"zcc"
127.0.0.1:6379> EXPIRE name 10 #设置过期时间
(integer) 1
127.0.0.1:6379> ttl name #查看当前key过期时间
(integer) 6
127.0.0.1:6379> ttl name
(integer) 3
127.0.0.1:6379> ttl name
(integer) -2
127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> type age
string
5.2String
127.0.0.1:6379> set key1 v1
OK
127.0.0.1:6379> get key1
"v1"
127.0.0.1:6379> APPEND key1 "hello"
(integer) 7
127.0.0.1:6379> get key1
"v1hello"
127.0.0.1:6379> APPEND key1 ",kuangshen"
(integer) 17
127.0.0.1:6379>
127.0.0.1:6379> STRLEN key1
(integer) 17
127.0.0.1:6379>
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> decr views
(integer) 0
127.0.0.1:6379> incrby views 10
(integer) 10
127.0.0.1:6379> get views
"10"
127.0.0.1:6379> set key1 "hello,kuangshen"
OK
127.0.0.1:6379> get key1
"hello,kuangshen"
127.0.0.1:6379> GETRANGE key1 0 3
"hell"
127.0.0.1:6379> GETRANGE key1 0 -1
"hello,kuangshen"
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 (set with expire) #设置过期时间
setnx (set if not exist) #不存在再设置,在分布式锁中经常使用
127.0.0.1:6379> setex key3 30 "hello"
OK
127.0.0.1:6379> ttl key3
(integer) 17
127.0.0.1:6379> setnx mykey "redis"
(integer) 1
127.0.0.1:6379> keys *
1) "key2"
2) "mykey"
3) "key1"
127.0.0.1:6379> keys *
(empty list or set)
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:3} #设置一个user:1对象 值为json字符
127.0.0.1:6379> mset user:1:name zhangsan user:1:age 18 #user:{id}:{field}
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "zhangsan"
2) "18"
#更新操作
127.0.0.1:6379> getset db redis
(nil)
127.0.0.1:6379> get db
"redis"
127.0.0.1:6379> getset db mysql
"redis"
127.0.0.1:6379> get db
"mysql"
String类:计数器,统计多单位的数量,粉丝数,对象缓存存储!
5.3 list
#
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> RPUSH list rfour
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
4) "rfour"
127.0.0.1:6379> LPOP list
"three"
127.0.0.1:6379> RPOP list
"rfour"
127.0.0.1:6379> LRANGE list 0 -1
1) "two"
2) "one"
127.0.0.1:6379> lindex list 0
"two"
127.0.0.1:6379> lindex list 1
"one"
127.0.0.1:6379> LPUSH list one two three
(integer) 3
127.0.0.1:6379> LLEN list
(integer) 3
##############################################################
# 删除元素 lrem key count value
127.0.0.1:6379> lrem list 1 one
(integer) 1
127.0.0.1:6379> Rpush mylist "hello" "hello1" "hello2" "hello3"
(integer) 4
127.0.0.1:6379> LRANGE mylist 0 -1
1) "hello"
2) "hello1"
3) "hello2"
4) "hello3"
127.0.0.1:6379> ltrim mylist 1 2 #通过下标截取,原来的去掉
OK
127.0.0.1:6379> LRANGE mylist 0 -1
1) "hello1"
2) "hello2"
######################################
#rpoplpush 移除列表最后一个元素,将他移动到新的列表中去
127.0.0.1:6379> rpush mylist one two three four
(integer) 4
127.0.0.1:6379> rpoplpush mylist myotherlist
"four"
127.0.0.1:6379> lrange mylist 0 -1
1) "one"
2) "two"
3) "three"
#############################################
#lset 将下标的值替换成另一个值,更新操作
127.0.0.1:6379> lrange mylist 0 -1
1) "one"
2) "two"
3) "three"
127.0.0.1:6379> lset mylist 0 zero
OK
127.0.0.1:6379> lrange mylist 0 -1
1) "zero"
2) "two"
3) "three"
###############################################################
#linsert 插入
127.0.0.1:6379> lrange mylist 0 -1
1) "one"
2) "two"
3) "three"
127.0.0.1:6379> lset mylist 0 zero
OK
127.0.0.1:6379> lrange mylist 0 -1
1) "zero"
2) "two"
3) "three"
127.0.0.1:6379> linsert mylist before two insert1
(integer) 4
127.0.0.1:6379> linsert mylist after two insert2
(integer) 5
127.0.0.1:6379> lrange mylist 0 -1
1) "zero"
2) "insert1"
3) "two"
4) "insert2"
5) "three"
- 实际是一个双向链表
- key不存在,创建新的链表,key存在,新增内容
- 移除所有值,空链表,也代表不存在
- 消息排队!消息队列(Lpush Rpop),栈(Lpush Lpop)
5.4 set
127.0.0.1:6379> sadd myset one #在set集合中加入元素
(integer) 1
127.0.0.1:6379> sadd myset two
(integer) 1
127.0.0.1:6379> smembers myset #在set集合中查找全部元素
1) "two"
2) "one"
127.0.0.1:6379> sismember myset one #在set集合中查找指定的元素
(integer) 1
127.0.0.1:6379> sismember myset three
(integer) 0
############################################
---------------------------------------------------------
127.0.0.1:6379> scard myset
(integer) 2
127.0.0.1:6379> srem myset one
(integer) 1
127.0.0.1:6379> scard myset
(integer) 1
127.0.0.1:6379> smembers myset
1) "two"
#######################################################
# randmember key 获取随机值
127.0.0.1:6379> sadd myset one two three four
(integer) 3
127.0.0.1:6379> smembers myset
1) "two"
2) "one"
3) "three"
4) "four"
127.0.0.1:6379> srandmember myset
"four"
127.0.0.1:6379> srandmember myset
"three"
127.0.0.1:6379> srandmember myset
"two"
127.0.0.1:6379> srandmember myset
"four"
####################################################
127.0.0.1:6379> smembers myset
1) "two"
2) "one"
3) "three"
4) "four"
127.0.0.1:6379> spop myset
"three"
127.0.0.1:6379> smembers myset
1) "two"
2) "one"
3) "four"
###################################################################
127.0.0.1:6379> smembers myset
1) "two"
2) "one"
3) "four"
127.0.0.1:6379> sadd myset2 set2
(integer) 1
127.0.0.1:6379> smove myset myset2 one
(integer) 1
127.0.0.1:6379> smembers myset2
1) "set2"
2) "one"
#############################################################
共同关注(交集)
127.0.0.1:6379> sadd key1 a b c
(integer) 3
127.0.0.1:6379> sadd key2 c d e
(integer) 3
127.0.0.1:6379> sdiff key1 key2 #差集
1) "a"
2) "b"
127.0.0.1:6379> sinter key1 key2 #交集
1) "c"
127.0.0.1:6379> sunion key1 key2 #并集
1) "e"
2) "b"
3) "c"
4) "d"
5) "a"
A用户将所有关注的人放在一个集合中,其粉丝也放在一个集合中
共同关注,共同好友,共同爱好,推荐好友
5.5hash
==map集合,和String差不多
127.0.0.1:6379> hset myhash field1 zcc #set key-<key,value>
(integer) 1
127.0.0.1:6379> hget myhash field1
"zcc"
127.0.0.1:6379> hmset myhash field1 hello field2 world
OK
127.0.0.1:6379> hmget myhash field1 field2
1) "hello"
2) "world"
127.0.0.1:6379> hgetall myhash #获取全部key-value
1) "field1"
2) "hello"
3) "field2"
4) "world"
#删除hash指定的key
127.0.0.1:6379> hdel myhash field1
(integer) 1
127.0.0.1:6379> hgetall myhash
1) "field2"
2) "world"
#
127.0.0.1:6379> hlen myhash
(integer) 1
#判断hash字段是否存在
127.0.0.1:6379> hexists myhash field1
(integer) 0
127.0.0.1:6379> hexists myhash field2
(integer) 1
##############################################
127.0.0.1:6379> hkeys myhash
1) "field2"
127.0.0.1:6379> hvals myhash
1) "world"
###################################
127.0.0.1:6379> hset myhash field3 5
(integer) 1
127.0.0.1:6379> hincrby myhash field3 1
(integer) 6
127.0.0.1:6379> hincrby myhash field3 -1
(integer) 5
127.0.0.1:6379> hsetnx myhash field4 hello #不能存在则创建
(integer) 1
127.0.0.1:6379> hsetnx myhash field4 world #存在则不创建
(integer) 0
hash 变更的数据user name age ,更适合来存储对象
6 、三大特殊数据结构
7、事务
MySQL ACID
原子性 一致性 隔离性 持久性
事务没有隔离级别概念
redis单条命令是原子性的,但是事务不保证原子性
redis事务:一组命令的集合,一个事务中所有命令都会被序列化,在事务执行过程中,会按照顺序执行
一次性、顺序性、排他性!
redis事务:
开启事务(multi),命令入队(…),执行事务(exec)
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> get k2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK
3) "v2"
4) OK
#################################################
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> discard #放弃事务
OK
127.0.0.1:6379> get k4
(nil)
# 编译时报错,符合原子性,全部命令都不执行
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> getset k2
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k3
(nil)
#运行时异常,事务不保证原子性
127.0.0.1:6379> set k1 "v1"
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr k1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> get k3
QUEUED
127.0.0.1:6379> exec
1) (error) ERR value is not an integer or out of range
2) OK
3) OK
4) "v3"
127.0.0.1:6379> get k2
"v2"
22、乐观锁