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简介

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/decrby

    • incr 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/setnx

    • setex key seconds value
      • 新增一条数据,key=value
      • 且设置该数据的生存时间为seconds,单位:秒
      • 若key存在,则覆盖
    • setnx key value
      • 如果key不存在,新增一条数据,key=value
      • 如果key存在,不做任何改变
  • mset/mget/msetnx

    • mset 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/hget

    • hset key field value
      • 若key不存在,则新增一条数据,其值是一个键值对,field-value的形式
      • 若key存在,则覆盖
    • hget key field
      • 获取指定的key的hash的key为field的数据
  • hmset/hmget/hgetall

    • hmset 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/hvals

    • hkeys 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/sismeber

    • sadd 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);

    }

}

posted @ 2019-11-08 20:03  神里的雾切  阅读(18)  评论(0)    收藏  举报