Redis
Redis
一.介绍NoSql
1.什么是NoSql
NoSql = Not Only Sql
不仅仅是Sql
泛指非关系型数据库
2.能干嘛
- 当数据量非常大的时候,使用关系型数据库访问效率较低,使用对应的NoSql数据提高访问的性能
- 易于扩展
- 数据结构非常的灵活
3.为什么用
在互联网刚兴起的时候,一个网站的访问量一般都不是很大,一般的数据库足以轻松的应对
随着互联网的火爆,网民的数据随之增加,很多的网站的访问量相当大,这时候,一般的数据库已经应对起来非常的吃力
因此需要开发一些适合大数据的数据库
NoSql数据库就是为了解决这些问题
4.互联网的3V+3高
- 3V
- Volume:海量
- Variety:多样
- velocity:实时
- 3高
- 高并发
- 高可扩
- 高性能
5.NoSql数据库四大分类
- 键值存储数据库
- 数据模型:key-value,value是一个无结构的数据
- 优点:数据没有格式的限制,易于扩展,查找速度较快
- 缺点:数据没有格式,通常只被当做字符串或者二进制数据
- 应用场景:内容缓存、大数据量的高访问负载、日志系统等
- 典型应用:redis
- 列存储数据库
- 数据模型:以列式进行存储,将同一列的数据存储在一起
- 优点:查找速度快,易于扩展,更容易进行分布式扩展
- 缺点:功能局限性较大
- 应用场景:分布式的文件系统,例如:博客平台、日志系统
- 典型应用:HBase
- 文档型数据库
- 数据模型:key-value,value是一个结构化的数据
- 优点:数据结构要求不严格,表结构可变化,不需要像关系型数据库一样预定义表结构
- 缺点:查询速度慢,缺乏统一的查询语法
- 应用场景:适合J2EE应用
- 典型应用:Mongodb
- 图形数据库
- 数据模型:图结构
- 优点:利用图结构的相关算法,可以快速的查找你所需要的信息
- 最短寻址算法
- N度关系算法
- 缺点:需要对完整的图结构做计算才能得出想要的信息
- 这种情况下就不适合做分布式集群方案
- 应用场景:社交网络、推荐系统
- 典型应用:Neo4J
6.NoSql数据库的特性
-
CAP
-
C:Consistency--一致性
-
A:Availability--可用性
-
P:Partition tolerance--分区容错性
-
三进二机制
- CP:Redis、Mongodb
- CA:传统的Oracle
- AP:大多数的网站架构选择的是AP
-
二.Redis简介
1.Redis是什么
Remote Dictionary Server
远程字典服务器
是一个开源的免费的内存数据库
基于内存运行,并支持持久化操作
2.优点
- 支持数据的读写
- 支持数据的持久化
- 支持一主多仆
- 主服务器负责写操作
- 从服务器负责读操作
- 支持数据订阅
- 读取数据的性能较高
3.安装Redis
-
下载对应版本的redis文件
- 建议使用linux
-
将redis解压到一个非中文无空格的目录中
tar -xvf redis-5.0.5.tar.gz -
编译
cd redis-5.0.5 make -
安装
make install #如果有权限,安装完成之后生成bin目录 #如果没有权限,在有权限的位置创建执行目录 cd ~ mkdir redis-bin cd ~/redis-5.0.5 make install PREFIX=~/redis-bin/ #安装完成之后生成bin目录 #redis中所有的执行命令都需要进入安装完成之后的bin目录中进行执行 #该目录中存放了redis的可执行程序 -
启动redis服务器
#本地启动方式 ./redis-server #指定端口号启动 ./redis-server --port 6380 #配置文件启动方式 ./redis-server 配置文件的路径名+文件名 -
启动redis客户端
- 连接指定的服务器
#连接本地redis服务 ./redis-cli #连接指定端口的redis服务 ./redis-cli -p 端口号 #连接指定的服务器上的redis服务 ./redis-cli -h ip -p port -
测试
- 在客户端中输入ping
- 如果返回pong表示成功
-
停止
- 方式一:快捷键Ctrl+C
- 方式二:客户端执行shutdown命令
三.Redis的数据类型
redis的5+1
五大数据类型+key
1.五大数据类型
- String
- 字符串
- String是Redis的最基本的数据类型
- 一个Redis中的String的数据量大小不能超过512M
- String是Redis中其他类型的基础
- 其他的数据类型本质上就是字符串的组织形式不同
- Hash
- 哈希
- 相当于Java中的Map类型
- 其值是一个键值对的集合
- 最终的体现形式:key-<key,value>
- ex:
user=<username=admin,password=123.....>
- List
- 列表
- 类似于Java中的List
- 有序、可重复
- 可以选择在列表的头部或者尾部插入数据
- Set
- 集合
- 类似于Java中的Set
- 无序、不可重复
- ZSet
- 有序集合
- Sorted Set
- 在Set的基础上加了一个字段,用来实现排序操作
- score分数字段,值只能是一个数字
2.List与ZSet
-
相同点
- 两者都是有序的
- 都可以获取某个范围的数据
-
不同点
-
List
- 是通过链表来实现的,因此其获取所有数据的头尾两端的速度非常快
- 当数据量越来越大时,获取中间数据的效率会越来越低
- 在访问两端数据的时候,List效率高
- 在插入数据的时候,List只能插入头部或者尾部的数据,即两端数据
-
ZSet
- ZSet是通过score分数字段来进行排序的
- 因此其访问任意位置的数据的效率都差不多
- 在访问中间数据的时候,ZSet效率高
- 在插入数据的时候,可以根据score插入任意位置
- ZSet比较消耗内存
-
四.常用命令
1.key
-
keys 指定的key- 返回指定的key是否存在
- 如果存在,返回存在的key有哪些
- 如果不存在,返回
(empty list or set) - 支持通配符
- keys *:查询所有的key
-
exists key1 key2 ...- 判断指定的key是否存在
- 如果存在返回存在的key有多少个
- 如果不存在返回0
-
expire key 时间(秒)- 设置指定的key的生存时间
- 即指定key在多少秒之后失效
- 如果时间为0,相当于删除操作
-
ttl key- 查询指定的key剩余的生存时间是多少
- 返回值为当前剩余的时间
- -2表示已经过期,实际上就是没有这个key
- -1表示永不过期,实际上就是没有设置生存时间
-
type key- 判断当前key的类型
- 返回值对应的是五大数据类型
-
del key1 key2 key3- 批量删除指定的key
-
flushdb- 清空当前库
2.string
-
set key value- 设置一个值
- 若key不存在,表示新增一条数据
- 若key已经存在,则表示覆盖对应的key的数据
-
get key- 获取指定的key的数据
- 如果数据是中文,默认方式查看不了
- 在登录客户端的时候可以使用
./redis-cli --raw的方式进行客户端的方式 - 通过该方式访问时可以查看中文数据
-
append key value- 设置一个值
- 若key不存在,则表示新增一条数据
- 若key存在,则修改对应的数据,表示将新的值追加到原有的数据的末尾,生成新的数据
-
strlen key- 获取指定的key的数据的长度
-
incr/decr/incrby/decrbyincr key- 将指定可以所对应的数据的值加1,key的值只能是数字
- 若key不存在,则新增一条数据,其值自动设置为1
decr num- 将指定可以所对应的数据的值减1,key的值只能是数字
- 若key不存在,则新增一条数据,其值自动设置为-1
incrby key num- 将指定可以所对应的数据的值加num,key的值只能是数字
- 若key不存在,则新增一条数据,其值自动设置为num
decrby key num- 将指定可以所对应的数据的值减num,key的值只能是数字
- 若key不存在,则新增一条数据,其值自动设置为-num
-
getrange/setrange-
getrange key begin end- 获取指定的begin位置到end位置的值
- 类似于Java中的subString方法,截取字符串
- 索引位置从0开始,包含开始与结束位置的字符
- 0 -1表示所有字符
-
setrange key index value- 将指定的key的数据从索引位置index开始的值替换成指定的数据value
- 当原有字符串剩余长度小于value的长度,则自动延长原字符串长度
- 当原有字符串剩余长度大于value的长度,则只替换对应长度部分的数据
set name admin setrange name 3 admin#此时name的值为admadmin setrange name 3 abc#此时name的值为admabcin
-
-
setex/setnxsetex key secondsvalue- 新增一条数据,key=value
- 且设置该数据的生存时间为seconds,单位:秒
- 若key存在,则覆盖
setnx key value- 如果key不存在,新增一条数据,key=value
- 如果key存在,不做任何改变
-
mset/mget/msetnxmset key1 value1 key2 value2 ...- 批量添加
- 相当于多次执行set操作
- 如果key存在,覆盖
- 如果key不存在,新增
mget key1 key2 key3- 批量获取指定key的数据
msetnx key1 value1 key2 value2...- 批量进行setnx操作
- 其中只要有任意一个key存在,则不做任何操作
-
getset key value- 先执行get操作,后执行set操作
- 返回的是原来key的数据
- 然后将指定的key的数据替换成新的数据value
- 相当于先执行了get key
- 后执行set key value
3.hash
-
hset/hgethset key field value- 若key不存在,则新增一条数据,其值是一个键值对,field-value的形式
- 若key存在,则覆盖
hget key field- 获取指定的key的hash的key为field的数据
-
hmset/hmget/hgetallhmset key f1 v1 f2 v2...- 批量添加hash中的数据
hmget key f1 f2...- 批量获取hash中指定filed的数据
hgetall key- 获取对应的hash中所有的数据
-
hdel key f2 f2..- 批量删除指定的hash中指定的filed的数据
-
hlen key- 获取指定的hash中元素的数量
-
hexists key filed- 判断指定的hash中对应的field是否存在
-
hkeys/hvalshkeys key- 返回指定的hash中所有的键值对中的field
hvals key- 返回指定的hash中所有的键值对中的value
-
hincrby key field num- 将指定的hash中field所对应的值加上num
- 此时的num必须是整数
-
hincrbyfloat key field num- 将指定的hash中field所对应的值加上num
- num可以是浮点数
-
hsetnx key field value- 若key不存在,则新增
- 若key存在,则不做任何操作
4.list
-
lpush key v1 v2...- 将多个数据插入到指定的列表的头部
- 如果指定的key不存在,新增
- 如果指定的key存在,追加
-
rpush key v1 v2...- 将多个数据插入到指定的列表的尾部
-
lrange key begin end- 获取列表中从指定位置begin到end位置的所有元素
- 0 -1表示查询所有的
-
lindex key index- 获取指定位置的元素
- 从头往尾数
-
llen key- 获取指定的列表的元素的数量
-
lpop key- 移除头部的第一个元素
- 返回值为当前移除的元素
-
rpop key- 移除尾部的第一个元素
- 返回值为当前移除的元素
-
lrem key count value- 从头部开始删除值为value的元素
- 总共删除count个
- 如果count的值为0,则表示删除所有值为value的元素
- 如果count的值大于值为value的元素的个数,则删除所有值为value的元素
-
ltrim key begin end- 截取从begin位置到end位置的子元素
- 且将截取后的子元素作为当前列表的新的值
- 实际上做了覆盖操作
-
rpoplpush 源列表 目标列表- 移除源列表中的尾部的第一个元素
- 并将该元素插入到目标列表中的头部的位置
-
lset key index value- 修改列表中指定位置的元素的数据
-
linsert key before/after v1 v2- 在指定的列表的元素v1之前/之后插入一个新的元素v2
- 如果指定的元素v1存在多个相同的,则操作的始终是第一个
5.set
-
sadd/smembers/sismebersadd key v1 v2...- 向一个set中添加多个值,无序的
- 如果key已经存在,则报错
smembers key- 返回指定的集合中的所有值
sismember key value- 判断集合中是否存在对应的key中的元素
- 如果存在返回1,否则返回0
-
scard key- 获取集合中元素的数量
-
srem key value- 删除集合中指定的元素
-
srandmember key- 随机返回集合中的一个元素
-
srandmemberkey num- 随机返回集合中num个元素
-
spop key- 随机删除集合中的某一个元素
- 并返回删除的元素是谁
-
spop key count- 随机删除集合中的count个元素
- 并返回删除的元素有哪些
-
smove key1 key2 value- 将key1集合中的value移动到key2的集合中
-
数学集合
- 差集
sdiff key1 key2...- 在前一个集合中存在,而后面的集合中不存在的元素
- 交集
sinter key1 key2...- 多个集合中都存在的元素
- 并集
sunion key1 key2...- 所有的集合中包含的所有的元素
- 差集
6.zset
-
zadd key score1 value1 score2 value2- 添加多个数据,score必须是数字
-
zrange key begin end- 返回begin位置到end位置的元素
- 0 -1表示所有
-
zrangebyscore key minscore maxscore- 返回score值在minscore与maxscore之间的所有元素
-
zrem key value1 value2...- 批量删除
-
zcard key- 获取指定的有序集合中元素的数量
-
zcount key min max- 获取分数在min与max之间的元素的个数
-
zrank key value- 获取有序集合中指定value的索引号
-
zscore key value- 获取有序集合中指定value的score值
-
zrevrank key value- 获取有序集合中指定value的索引号
- 按照分数降序排序
-
zrevrange key start stop- 获取有序集合中索引在start到stop之间的所有元素
- 按照分数降序排序
-
zrevrangebyscore key max min- 获取有序集合中分数在max到min之间所有的元素
- 按照分数降序排序
五.事务
1.什么是事务
所谓的事务,表示的是一组不可再分的操作序列
这些操作序列要么同时执行,要么同时不执行
是一个不可分割的完整的工作单元
2.redis事务操作
- multi
- 标记一个事务的开始
- 即开启事务
- discard
- 放弃执行事务中的所有命令
- 即回滚
- exec
- 执行事务中所有的命令
- 即提交
3.redis事务的四种情形
- 正常执行
- 正常的执行事务的开启与提交
- 正常回滚
- 正常的执行事务的开启与回滚
- 全体连坐
- 在事务的操作过程中有一个命令出错
- 那么所有的命令均不会执行
- 在执行的时候出现了语法出错
- 类似于Java代码的编译错误
- 这种情况就会自动回滚
- 冤有头债有主
- 在事务的操作过程中
- 谁出错了,则谁的操作不执行,但是其他操作正常执行
- 出错的操作不会影响到其他操作的执行
- 在执行的语法没错,但是运行出错
- 相当于Java代码的运行出错
六.消息订阅
是进程间的一种消息通信模式
发送者(pub)发送消息
订阅者(sub)接收消息
#普通方式
#订阅指定人员的消息
subscribe 第一个人的名字 第二个人的名字 第三个人的名字 ...
#被订阅者开始发布消息
#消息的值如果存在空格,需要使用双引号
#当发布者发布消息的时候,如果有人订阅了该人员的消息
#则会在订阅者的客户端展现其所发布的消息
publish 发布者的名字 消息
#支持通配符
#订阅者订阅消息
#可以直接使用*表示匹配所有人
psubscribe c*
#发布者发布消息
publish c1 "Hello Redis"
七.主从复制
主机master数据更新厚根据配置和策略
自动同步到从机的slave中的机制
Master以写为主
slave以读为主
可以帮我们实现读写的分离
提高服务器的负载能力
- 准备多台服务器
#配置主机
./redis-server
#配置从机,slaveof 主机ip 主机端口
./redis-server --port 6380 --slaveof 127.0.0.1 6379
- 开启客户端访问对应的服务器
#配置主机客户端
./redis-cli
#配置从机客户端
./redis-cli -p 6380
- 操作
- 默认情况下
- 主机中可以执行读写操作
- 从机只能执行读操作
- 可以通过配置文件将从机改为可以执行写操作
- 如果将从机改为可以执行写操作
- 但是此时的从机依然是无法影响到主机的
- 在配置文件中找到
slave-read-only yes配置项 - yes表示只读,改为no表示可以写
- 写操作也只是在当前的从机中执行,无法影响到主机
- 在redis5中取消了该配置
- 默认情况下
八.持久化
在运行过程中,redis是将数据保存在内存中
如果没有使用持久化,当服务器关闭之后,内存中的数据会被清空
为了让这些数据在服务器重启之后依然可用
redis提供了两种持久化方式
1.RDB
1-1 什么是RDB
Redis Database
将数据的快照以二进制的方式保存在硬盘中
在指定的时间间隔内,将内存中的数据快照保存到磁盘中
后面的数据快照会将前面锁保留的数据快照覆盖
RDB文件是一个以
*.rdb结尾的文件,默认为dump.rdb当服务器重启之后,自动读取所保存的快照文件
将快照文件中的数据恢复到内存中
如果在启动之后,RDB文件被删除,则启动之后,数据库中数据全部丢失
1-2 快照文件的保存时间间隔
################################ SNAPSHOTTING ################################
#
# Save the DB on disk:
#
# save <seconds> <changes>
#
# Will save the DB if both the given number of seconds and the given
# number of write operations against the DB occurred.
#
# In the example below the behaviour will be to save:
# after 900 sec (15 min) if at least 1 key changed
# after 300 sec (5 min) if at least 10 keys changed
# after 60 sec if at least 10000 keys changed
#
# Note: you can disable saving completely by commenting out all "save" lines.
#
# It is also possible to remove all the previously configured save
# points by adding a save directive with a single empty string argument
# like in the following example:
#
# save ""
#在900秒范围内,发生了一次变化
save 900 1
#在300秒范围内,发生了10次变化
save 300 10
#在60秒范围内,发生了10000次变化
save 60 10000
1-3 如何恢复数据
根据配置文件中所配置的rdb文件名
# The filename where to dump the DB
#配置rdb文件是谁,默认为dump.rdb
dbfilename dump.rdb
将对应的rdb文件存放到src目录下
当服务器启动时,会自动读取配置文件中所指定的rdb文件
将该文件中的数据恢复到数据库中
1-4 如何生成快照文件
- 自动
- 根据在配置文件中所配置的时间间隔自动生成rdb文件
- 手动
- 通过调用命令,立刻生成当前的快照
1-5 命令
- save
- 直接在当前进程中调用save命令
- 此时会阻塞当前的主进程
- 阻塞一直到数据保存完成为止
- 在主进程阻塞的期间,服务器不能处理任何一个客户端的请求
- 是一个同步的操作
- 优点
- 不会额外的消耗内存
- 缺点
- 阻塞主进程,阻塞客户端命令,执行效率低
- bgsave
- fork出一个子进程
- 由子进程进行调用保存命令,生成对应的快照文件
- 保存完成之后,会发送信号告诉主进程保存已经完成
- 由于保存操作是在子进程中执行的
- 因此它不会阻塞到主进程的操作
- 优点:
- 不会阻塞到主进程的任何操作
- 缺点:
- 由于子进程复制了一个与主进程完全一致的进程
- 那么会额外的消耗大量的内容
- 服务器的压力会变的很大
- fork
- 其实就是一个复制的操作
- fork的作用就是复制一份与当前一模一样的进程作为当前的子进程
- 子进程中所有的信息都与主进程完全的一致
- 相当的消耗内存
1-6 优缺点
- 优点
- 适合大规模的数据的恢复
- 对于数据的完整性与一致性的要求没有那么严格
- 缺点
- 在一定的时间间隔内会做一次备份
- 该备份会将原有文件替换调用
- 如果在替换过程中出现了意外
- 会导致数据的丢失
- 如果进行fork
- 会将内存中国的数据拷贝一份
- 此时非常的消耗内存
- 增大服务器的压力
- 在一定的时间间隔内会做一次备份
2.AOF
2-1 什么是AOF
以文本的方式,将所有对于数据执行的写入操作的命令记录下来
将其记录到对应的AOF文件中
以此到达保存数据的目录
以日志的形式记录每次执行写入操作的命令
每一次都会在原有的内容基础上追加新的操作
2-2 开启AOF
默认情况下,redis使用的RDB方式进行持久化
如何开启AOF
打开配置文件,找到APPEND ONLY MODE相关配置
-
appendonly
- 表示使用启用AOF进行持久化
- 默认值为no表示不起用
- 将其改为yes表示启用
-
appendfilename
- 配置AOF持久化的文件名
- 默认为:
appendonly.aof
-
appendfsync
- 配置AOF的保存模式,值有三种
- always
- 表示每一次运行写入命令都会将该命令写入到文件中
- 每执行一个命令,保存一次
- everysec
- 默认值
- 每一秒同步一次数据
- 保存操作是由子进程执行
- no
- 本身自己是不执行保存操作
- 等操作系统做数据缓存的同时进行同步的保存
- 会阻塞主进程
2-3 去除冗余文件
- auto-aof-rewrite-percentage 100
- 当目前的AOF文件超过了上次重写的文件的百分之多少的时候,会进行重写
- auto-aof-rewrite-min-size 64mb
- 限制了允许重写的AOF的文件的最小需要多大
2-4 优缺点
- 优点
- AOF保存文件的操作是一个追加操作
- 不存在数据丢失的风险
- 缺点
- AOF文件中存在着大量的冗余数据
- 非常的消耗内存
- 且运行效率是远远的低于RDB的
九.Jedis
Java-Redis
1.POM配置
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.1.0</version>
</dependency>
2.Jedis使用
在Jedis中所使用的一切方法都与命令完全一致
public static void main(String[] args) {
Jedis jedis = new Jedis("127.0.0.1",6379);
System.out.println(jedis.ping());
// jedis.set("name","admin");
// jedis.set("s1","v1");
// jedis.set("s2","v2");
// System.out.println(jedis.keys("*"));
// Set<String> keys = jedis.keys("*");
// for(String s : keys){
// System.out.println(jedis.get(s));
// }
// jedis.lpush("l1","v1","v2");
System.out.println(jedis.lrange("l1",0,-1));
}
十.SpringBoot-Redis
1.POM配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.58</version>
</dependency>
2.application配置
#redis默认的数据库索引号,默认0
#redis密码默认为空
spring:
redis:
database: 0
host: 127.0.0.1
port: 6379
password:
3.使用
在SpringBoot整合redis中
提供了一个模板类StringRedisTemplate
@SpringBootTest
class SpringbootRedisApplicationTests {
@Autowired
private StringRedisTemplate redisTemplate;
@Test
void contextLoads() {
//判断key是否存在
// System.out.println(redisTemplate.hasKey("aaa"));
System.out.println("name的值为:"+redisTemplate.opsForValue().get("name"));
//向Hash中存数据
// Map<String,String> map = new HashMap<>();
// map.put("username","admin");
// map.put("password","123456");
// map.put("phone","13812345678");
// map.put("address","江苏-南京");
// map.put("id","1");
// redisTemplate.opsForHash().putAll("map",map);
User user = new User();
user.setId(1);
user.setUsername("admin");
user.setPassword("666666");
user.setPhone("13812345678");
user.setAddress("江苏-南京");
String userJson = JSON.toJSONString(user);
redisTemplate.opsForValue().set("user",userJson);
}
}

浙公网安备 33010602011771号