NoSQL 数据库
redis 键值型数据库
- 官方只提供了linux 版本
- 如果希望在 windows 下尝试 redis
- 安装虚拟机 virsual box, vmware --> 装 linux --> 装 redis
- docker 来使用 redis
- redis 的 windows 版本,版本较低,不适合生产环境
启动 redis 服务器端
redis-server
停止 -> 关闭窗口或是按Ctrl+C
启动 redis 客户端
redis-cli
1. 基础数据结构
- string 字符串
- list 队列,栈 --> linkedList
- set 集合,元素唯一
- hash 类似 hashMap
- zset 跳表结构 有序的set集合
1.1 string
- 数据结构:SDS(simple dynamic string) 可变 如何扩容
- 在容量满了会自动扩容, 在容量小于 1m 时,每次翻倍, 超过 1m 每次只增加 1m,最多512m
- set get
set key value --> 存储 value 为字符串类型的数据
get key --> 根据 key 获取字符串类型的数据
- mset --> 一次存储多个键值对
- mget --> 根据多个 key, 一次获取多个值
- expire --> 设置超时时间
expire key 超时时间(秒)
- ttl --> 查看某个 key 剩余的超时时间
- set [ex] [nx]
- 其中 nx 含义是,不存在key时,set操作才会成功,如果key有了,set操作会返回nil(不会覆盖原有的key)
- 场景 可以用于实现 redis 的分布式锁
- incr 针对 value 是数字时, 每次自增1
- incrby 针对 value 是数字时, 每次自增n
1.2 list
-
数据结构:
- ziplist --> 当list中数据量很少时,数据连续存储,访问效率高
- quicklist --> 当list 中数据量多时,是一个双向链表,空间利用率高
-
lpush --> 从左侧向集合添加元素
[3, 2, 1]
lpush 1
lpush 2
lpush 3 -
rpop --> 从右侧弹出元素
rpop 返回1, 集合中还剩 [3,2] -
lpush + rpop 行为上是一个队列(先入先出 FIFO)
-
rpush + lpop 行为上是一个队列(先入先出 FIFO)
-
lpush + lpop 行为上是一个栈 (先进后出 )
-
rpush + rpop 行为上是一个栈 (先进后出 )
-
llen --> 查看集合的长度
-
ltrim --> 对列表进行截取,格式为 key start(起始下标) stop(结束下标)
-
lindex --> 按下标获取元素, 效率较低,格式: key index(元素下标)
-
lrange --> 格式是 key start(起始下标) stop(结束下标),其中-1表示到列表的最后
-
用途
- 抢购
- 消息队列-不可靠
1.3 hash
- 数据结构:hash 表(数组+链表)
- 渐进式扩容,扩容过程中会查询新旧两个hash表,不会影响客户的使用,扩容结束才用新的hash表替换掉旧的hash表
key - 用户
- name zhangsan
- age 18
- hset 格式
hset key 子属性 属性值
- hget 格式
hget key 子属性
- hgetall
- hlen --> 查看hash表中有几组属性
- hincrby
- 对比字符串
- hash 结构可以把一些相关的子key(子属性)集中在一起统一管理, 可以对其中属性进行独立处理
- 存储消耗上要高于字符串
1.4 set(唯一)
- 数据结构: hash 表(数组+链表)只是仅用了其中key,来保证元素的唯一
- sadd 格式
sadd key 元素
-->添加元素 - smembers 格式
smembers key
-->查看所有元素 - sismember 格式
sismember key 待测试的元素
-->判断元素是否包含在集合中,包含返回1,不包含返回0 - scard --> 获取集合大小
- spop --> 随机找一个元素移除
1.5 zset (唯一并有序)
- zadd 格式
zadd key 得分 元素
注意默认得分低的排在前面 - zrange 格式
zrange key start(起始下标) stop(结束下标)
- zrevrange 格式
zrevrange key start(起始下标) stop(结束下标)
- zcard --> 查看大小
- zscore --> 查看某个元素的得分 格式
zscore key 元素
返回得分 - zrank --> 查看某个元素的排名 排名从0开始
- zrangebyscore -inf --> 给一个分数范围,根据此范围定位符合的元素
- zrem --> 删除集合中的元素
- 数据结构- 跳跃表(多层的链表结构,减少比较次数)
1.6 后四种容器
- create if not exists --> 第一次操作时才创建这些集合
- drop if no elements --> 如果集合空了,会把集合删除, 内存释放掉
- expire 过期时间
2. 通用操作
2.1
del 根据 key 删除
flushall 清空整个 redis,删除所有的 key
2.2 遍历
- keys 匹配关键字 --> 根据匹配关键字,查找所有符合的key
keys *
千万不要在线上环境使用
- scan 每次只查询一部分符合匹配关键字的结果,不会像 keys 查询所有
scan 0 match a*
1) "100" -- 如果返回的是0 表示没有更多的结果了,但如果是其他数字,说明结果没完
2) 1) "a3"
1) "a2"
2) "a1"
scan 100 match a*
1) "200" -- 如果返回的是0 表示没有更多的结果了,但如果是其他数字,说明结果没完
2) 1) "a3"
1) "a2"
2) "a1"
scan 200 match a*
1) "0" -- 如果返回的是0 表示没有更多的结果了,但如果是其他数字,说明结果没完
2) 1) "a3"
1) "a2"
2) "a1"
3. 使用java 代码操作 redis 库
-
用 try-with-resources语法保证 redis 连接用完后还回连接池
-
把连接池的配置信息放入 application.properties 配置文件中
- 方法1:
@Value(${配置文件的key})
属性 用@Value读取了配置文件的中值注入属性 - 方法2:把
@ConfigurationProperties
注解加在类上,它可以专门和配置文件中的一组配置相对应,先前缀匹配,后属性匹配
- 方法1:
-
如何将一个 java 对象存入 redis 库? 序列化
- 把java对象变成字节数组
- 把java对象变成 json 字符串
4. redis io 模型
- 单线程,单线程为什么还快
-
- 所有键值信息都存储在内存当中
-
- 单线程被充分利用
-
- 非阻塞io non-blocking-io
- select 轮询 (所有操作系统都支持)
- epoll 事件机制, 由操作系统通知线程,哪个连接有io操作,线程可以只关心这些有事件通知的连接 (linux)
5. 持久化
- RDB fork 子进程,读写分离,子进程读,父进程写(bgsave)save
- 内存快照
- save 会暂停其他客户端的使用
- bgsave 不会影响(暂停)其他客户端的使用, bgsave 会fork 子进程进行快照操作
- fork 子进程 - 子进程与主进程共享内存, 子进程负责将快照内容写入磁盘,主进程负责响应客户端指令, 他俩是并行执行的
- 内存快照
- AOF 先执行指令,再存盘
- 默认没有启用 通过appendonly = yes 启用
- 把所有增、删、改相关的命令及数据存入 aof 文件
- set name zhangsan
6. 事务
仅满足串行隔离性,不满足原子性
multi 代表事务开始
set k1 v1
set k2 v2
set k3 v3
exec 让以上命令执行, 其他客户端命令在exec 完毕之前,不能干扰
没有回滚特性(没有真正的原子性)
一个事务内,如果后面的命令执行失败,不会导致前面成功的命令回滚
discard 仅能在 exec 前撤销
乐观锁
while(true) {
jedis.watch(key); // 盯住一个 key
tx = jedis.multi(); // 返回事务对象
// 多条修改操作, 只是入队,还没有执行
tx.exec(); // 真正执行修改,
--> 结果如果不是空,表示没人干扰,我修改成功,退出循环
--> 结果是空, 表示其他人干扰了,我修改进入循环重试
}
7. 主从
slaveof host
slaveof no one