Redis

1.NoSql
# NoSql(Not Only Sql),不仅仅是sql,泛指非关系型数据库
2.NoSql的诞生
 随着互联网web2.0网站的兴起,传统的关系型数据库在高并发和特大规模的纯动态网站已经显得力不从心,暴露了很多难以克服的问题,如图片、音频、视频的存储等,传统数据库只能存储结构化的数据,而对于非结构的数据支持不够完善,NoSql这门技术,更好的解决了这些问题,它告诉世界不仅仅是sql.
3.NoSql数据库的四大分类
# 键值对(key-value)存储数据库这一类数据库主要会使用到一个哈希表,这个表中有一个特定的键和一个指针指向特定的数据.
优点:key/value模型对于IT系统来说,优势在于简单、易部署.
缺点:如果DBA(database admin)只对部分值进行查询或更新的时候,key/value就显得效率低下.
常见数据库:Redis
# 列存储数据库这类数据库通常是应对分布式存储的海量数据.
特点:键依然存在,但是它是指向了多个列.这些列是由列家族来安排的
常见数据库:HBase
# 文档型数据库文档型数据库的灵感来源于Lotus Notes办公软件,它的存储同键值存储相类似Bson--->Json  {"id":"1","name":"554"}
优点:该类型的数据模型是版本化的文档,半结构化的文档以特定的格式存储,比如Json.文档型数据库可以看做是键值数据库的升级版,允许之间嵌套键值.而且文档型数据库比键值数据库的查询效率更高
缺点:相较而言,事务支持不友好
常见数据库:MongDb
# 图形(Graph)数据库---图片 音频 视频  (一般会放到文件服务器)图形结构的数据库同其他行列以及刚性结构的SQL数据库不同,它是使用灵活的图形模型,并且能够扩展到多个服务器上
** NoSQL数据库没有标准的查询语言(SQL),因此进行数据库查询需要制定数据模型.许多NoSQL数据库都有REST式的数据接口或者查询API.如:Neo4J、InfoGrid、Infinite Graph.
4.NoSql适用场景
1.数据库类型比较简单
2.需要灵活性更强的IT系统
3.对数据性能要求较高(读)
4.不需要高度的数据一致性 NoSql弱化事务/没有事务
5.对于给定key,比较容易映射复杂值的环境(redis)
5.什么是Redis
# redis是一个开源(bsd许可)的内存数据结构存储,用作数据库、缓存和消息代理.
6.Redis的特点
1.Redis是一个高性能key/value内存型数据库
2.Redis支持丰富的数据类型(String,list,set,zset,hash)
3.Redis支持数据持久化---将内存中的数据持久化到磁盘
4.Redis单线程,单进程且效率高(不支持并发操作)
7.Redis安装
1.下载redis
2.准备一台机器安装redis(redis的底层由c编写)
3.将redis上传到linux系统中并解压4.编译安装redis   a)进入redis,解压安装包  b)安装gcc (yum install -y gcc)c)执行make命令     如果出现 zmalloc.h:50:31:致命错误:jemalloc/jemalloc.h:没有那个文件或目录   make MALLOC=libc    d)安装 make install 会直接安装到当前的redis的源码包,日后找起来不方便 make install PREFIX=/usr/redis  e)进入redis的安装目录 bin 用来存放redis中可执行二进制文件 启动 关闭 等文件 启动redis服务脚本:    redis-server./redis-server连接redis客户端脚本:  redis-cli./redis-cli -p 端口号 -u 主机ip       注意:redis 默认端口号为 6379

8.Redis中key相关指令
redis存储的数据是以 key value 形式存储 (key都为string)
1.删除指定的keydel key1 key2 ...   删除一到多个key
2.查看keykeys *               查看所有的keykeys h?llo          ?  代表匹配任意一个字符keys h*llo         *  代表匹配零到多个字符keys h[ae]llo      [] 匹配一个[]中包含的字符
3.判断某个key是否存在exists key ...     判断一个key或多个key是否存在
4.给已经存在的key设置过期时间expire key(单位 秒)           如验证码的过期时间
5.切换库(redis只有16个库,默认使用的是0库)select 库的编号(可用编号 0-15)
6.移动key到指定的DBmove key 库的编号
7.给已经存在的key设置过期时间pexpire key(单位 毫秒)
8.查看key的过期时间ttl key 返回单位 秒注意:返回 -1  代表key永久存在返回 -2  代表key不存在返回 >=0 代表key过期时间
9.查看key过期时间pttl key 返回单位 毫秒返回 -1  代表key永久存在返回 -2  代表key不存在返回 >=0 代表key过期时间
10.随即返回一个keyrandomkey
11.修改key的名字rename key newkey
12.查看key对应值的类型type key值的类型:stringlistsetzsethash
9.Redis中常用的数据库相关的指令
说明 :  使用redis的默认配置器动redis服务后,默认会存在16个库,下标从0-15
可以使用select 库的编号 来选择一个redis的库
1.  清空当前的库   flushdb
2.  清空全部的库   flushall
3.  ./redis-cli -p 端口号 -u 主机ip --raw  展示中文

10.Redis的 String 类型的操作 key value

1.命令

命令 说明
set 设置一个key/value
get 根据key获得对应的value
mset 一次设置多个key value
mget 一次获得多个key的value
getset 返回原始key的值,同时设置新值
strlen 获得对应key存储value的长度
append 为对应key的value追加内容 返回值是追加内容后字符串的长度
getrange 截取value的内容(下标0 开始)
setex 设置一个key存活的有效期(秒)新添加key的同时添加过期时间
psetex 设置一个key存活的有效期(豪秒)新添加key的同时添加过期时间
setnx 存在不做任何操作,不存在添加
msetnx 可以同时设置多个key,原子操作(只要有一个key存在就不做任何操作)
decr 进行数值类型的-1操作
decrby 根据提供的数据进行减法操作
Incr 进行数值类型的+1操作
incrby 根据提供的数据进行加法操作
incrbyfloat 根据提供的数据加入浮点数

11.Rdeis的List类型的操作

1.图示

2.命令

命令 说明
lpush 将某个值加入到一个key列表头部
lpushx 同lpush,但是必须要保证这个key存在
rpush 将某个值加入到一个key列表末尾
rpushx 同rpush,但是必须要保证这个key存在
lpop 返回和移除列表的第一个元素
rpop 返回和移除列表的最后一个元素
lrange 获取某一个下标区间内的元素(遍历所有 0 -1)
llen 获取列表元素个数
lset 设置某一个指定索引的值(索引必须存在)
lindex 获取某一个指定索引位置的元素
lrem 删除重复元素 lrem key 数字 值 数字:删除的个数
ltrim 保留列表中特定区间(index的区间)内的元素
linsert 在某一个元素之前或之后插入新元素

12.Redis的Set类型的操作

1.图示

2.命令

命令 说明
sadd 为集合添加元素
smembers 显示集合中所有元素 无序
scard 返回集合中元素的个数
spop 随即删除n个元素,并返回对应删除的n个元素 n—>数字
smove 从一个集合中向另一个集合移动元素 smove source(原始集合) destination(目标集合) member(元素)
srem 从集合中删除指定的member(1-n个)
sismember 判断一个集合中是否含有这个元素
srandmember 随机返回元素 默认返回一个,可以手动指定返回元素的个数
sdiff 去掉第一个集合中其它集合含有的相同元素
sinter 求交集
sunion 求和集

13.Redis的ZSet类型的操作

1.图示 ZSet ===> ScoreSet(分数set) ===> SortSet(排序set)

2.命令

命令 说明
zadd 添加一个有序集合元素
zcard 返回集合的元素个数
zrange 返回一个范围内的元素(zrange zset 0 -1 withscores 遍历所有并展示分数)
zrangebyscore 按照分数查找一个范围内的元素
zrank 返回排名(返回index)
zrevrank 倒序排名(返回index)
zscore 显示某一个元素的分数
zrem 移除某一个元素
zincrby 给某个特定元素加分

14.Redis的Hash类型的操作

1.图示

2.命令

命令 说明
hset 设置一个key/value对
hget 获得一个key对应的value
hgetall 获得所有的key/value对
hdel 删除某一个key/value对
hexists 判断一个key是否存在
hkeys 获得所有的key
hvals 获得所有的value
hmset 设置多个key/value
hmget 获得多个key的value
hsetnx 设置一个不存在的key的值
hincrby 为value进行加法运算
hincrbyfloat 为value加入浮点值

15.Redis中的小细节
1.redis中的端口号默认为 63791.如何修改redis默认端口:a)将源码包中的redis.conf 移动到 redis的安装目录/bin 下b)vim redis.conf  修改  port 自定义端口号注意: 想要配置的端口号生效,必须启动redis的同时加载配置文件./redis-server redis.conf./redis-cli -p 自定义端口号
2.redis中默认存在16个库1.修改库的数量vi redis.confdatabases 自定义数量(小于等于16)
3.redis以 后台进程启动vi redis.confdaemonize(守护进程) yes (后台启动)
4.redis可视化操作工具redis-desk-manager 客户端工具#注意:#默认redis服务器只能被本地连接访问 #想要远程访问,必须开启远程访问权限#vim redis.conf#修改 bind 0.0.0.0   所有客户端都可以访问

16.Redis中的持久化机制
1.什么是Redis的持久化
#将redis中的数据存储到硬盘里面
#在redis中的操作的是内存中的数据
2.Redis两种持久化方式
#快照(snapshotting)也称RDB      快照持久化(默认开启)
#AOF(append only file)         只追加文件
3.两大持久化机制
  1. 快照持久化

    定义:这种方式可以将某一时刻的所有数据都写入硬盘中,当然这也是redis的默认持久化方式,保存的文件是以.rdb形式结尾的文件因此这种方式也称之为RDB方式
    
    a) 快照持久化也是redis中的默认开启的持久化方案, 根据redis.conf中的配置,快照将被写入dbfilename指定的文件里面(默认是dump.rdb文件中)
    b)  根据redis.conf中的配置,快照将保存在dir选项指定的路径上
    c)  创建快照的几种方式
    
    1.客户端可以使用BGSAVE命令来创建一个快照,当接收到客户端的BGSAVE命令时,redis会调用fork¹来创建一个子进程,然后子进程负责将快照写入磁盘中,而父进程则继续处理命令请求#名词解释 : fork当一个进程创建子进程的时候,底层的操作系统会创建该进程的一个副本,在类unix系统中创建子进程的操作会进行优化:在刚开始的时候,父子进程共享相同内存,直到父进程或子进程对内存进行了写之后,对被写入的内存的共享才会结束服务(不会阻塞redis服务)
    
    2.客户端还可以使用SAVE命令来创建一个快照,接收到SAVE命令的redis服务器在快照创建完毕之前将不再响应任何其他的命令#注意 :  SAVE命令并不常用,使用SAVE命令在快照创建完毕之前,redis处于阻塞状态,无法对外服务
    
    3.当redis通过shutdown指令接收到关闭服务器的请求时,会执行一个save命令,阻塞所有的客户端,不再执行客户端执行发送的任何命令,并且在save命令执行完毕之后关闭服务器
    
    4.如果用户在redis.conf中设置了save配置选项,redis会在save选项条件满足之后自动触发一次BGSAVE命令,如果设置多个save配置选项,当任意一个save配置选项条件满足,redis也会触发一次BGSAVE命令
    save   时间(秒)  key变化次数
    save    900          1
    save    300          10
    save     1          10000
    
  2. AOF持久化(默认不开启)

    定义:这种方式可以将客户端执行的所有写命令记录到日志文件中
    
    1.开启AOF   vim redis.confappendonly yes                   开启appendfilename "appendonly.aof"  日志名字为appendonly.aof日志文件生成的位置与快照的路径一致
    2.日志的同步频率# appendfsync alwaysappendfsync everysec(默认使用)# appendfsync no
    
    选项 同步频率
    always 每个redis写命令都要同步写入硬盘,严重降低redis速度
    everysec 每秒执行一次同步显式的将多个写命令同步到磁盘
    no 由操作系统决定何时同步

    三种日志记录频率的详细分析 :

    1.如果用户使用了always选项,那么每个redis写命令都会被写入硬盘,从而将发生系统崩溃时出现的数据丢失减到最少;遗憾的是,因为这种同步策略需要对硬盘进行大量的写入操作,所以redis处理命令的速度会受到硬盘性能的限制;注意 :  转盘式硬盘在这种频率下200左右个命令/s ; 固态硬盘(SSD) 几百万个命令/s;警告 :  使用SSD用户请谨慎使用always选项,这种模式不断写入少量数据的做法有可能会引发严重的写入放大问题,导致将固态硬盘的寿命从原来的几年降低为几个月
    
    2.为了兼顾数据安全和写入性能,用户可以考虑使用everysec选项,让redis每秒一次的频率对AOF文件进行同步;redis每秒同步一次AOF文件时性能和不使用任何持久化特性时的性能相差无几,而通过每秒同步一次AOF文件,redis可以保证,即使系统崩溃,用户最多丢失一秒之内产生的数据(推荐使用这种方式)
    
    3.最后使用no选项,将完全有操作系统决定什么时候同步AOF日志文件,这个选项不会对redis性能带来影响但是系统崩溃时,会丢失不定数量的数据,另外如果用户硬盘处理写入操作不够快的话,当缓冲区被等待写入硬盘数据填满时,redis会处于阻塞状态,并导致redis的处理命令请求的速度变慢(不推荐使用)
    

    3.AOF重写

        aof 的方式也同时带来了另一个问题。持久化文件会变的越来越大。例如我们调用incr test命令100次,文件中必须保存全部的100条命令,其实有99条都是多余的。因为要恢复数据库的状态其实文件中保存一条set test 100就够了。为了压缩aof的持久化文件Redis提供了AOF重写机制
    

    1.重写AOF文件两种方式

    a. 执行BGREWRITEAOF命令b. 配置redis.conf中的auto-aof-rewrite-percentage选项
    

    a. 执行BGREWRITEAOF命令

    1. redis调用fork ,现在有父子两个进程 子进程根据内存中的数据库快照,往临时文件中写入重建数据库状态的命令2. 父进程继续处理client请求,除了把写命令写入到原来的aof文件中。同时把收到的写命令缓存起来。这样就能保证如果子进程重写失败的话并不会出问题。3. 当子进程把快照内容已命令方式写到临时文件中后,子进程发信号通知父进程。然后父进程把缓存的写命令也写入到临时文件。4. 现在父进程可以使用临时文件替换老的aof文件,并重命名,后面收到的写命令也开始往新的aof文件中追加。#注意 :  重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,替换原有的文件这点和快照有点类似。(AOF重写过程完成后会删除旧的AOF文件,删除一个体积达几十GB大的旧的AOF文件可能会导致系统随时挂起 )
    

    b. 配置redis.conf中的auto-aof-rewrite-percentage选项

    1. AOF重写也可以使用auto-aof-rewrite-percentage 100和auto-aof-rewrite-min-size 64mb来自动执行BGREWRITEAOF.#说明: 如果设置auto-aof-rewrite-percentage值为100和auto-aof-rewrite-min-size 64mb,并且启用的AOF持久化时,那么当AOF文件体积大于64M,并且AOF文件的体积比上一次重写之后体积大了至少一倍(100%)时,会自动触发,如果重写过于频繁,用户可以考虑将auto-aof-rewrite-percentage设置为更大
    

    4.两种持久化方案的总结

AOF持久化既可以将丢失的数据的时间降低到1秒(甚至不丢失任何数据),那么我们还有什么理由不是用AOF呢?


~~~javascript
#注意 : 这个问题实际上并没有这么简单,因为redis会不断将执行的写命令记录到AOF文件中,所以随着redis运行,AOF文件的体积会不断增大,在极端情况下甚至会用完整个硬盘,还有redis重启重新执行AOF文件记录的所有写命令的来还原数据集,AOF文件体积非常大,会导致redis执行恢复时间过长两种持久化方案既可以同时使用,又可以单独使用,在某种情况下也可以都不使用,具体使用那种持久化方案取决于用户的数据和应用决定无论使用AOF还是快照机制持久化,将数据持久化到硬盘都是有必要的,除了持久化外,用户还应该对持久化的文件进行备份(最好备份在多个不同地方)
17.SpringData操作Redis
  1. 使用spring-data操作redis

    Spring-Data-Redis项目(简称SDR)对Redis的Key-Value数据存储操作提供了更高层次的抽象,类似于Spring Framework对JDBC支持一样。

    Spring Data Redis使得在Spring应用中读写Redis数据库更加容易

  2. 连接Redis服务(单机)

    在Spring Data Redis中通过org.springframework.data.redis.connection包中的RedisConnection和RedisConnectionFactory类来获取Redis连接。

  3. 连接redis服务集群

  4. RedisTemplate的支持

    熟悉Spring的JdbcTemplate对象的话,应该大概能猜出来RedisTemplate的作用了,RedisTemplate对象对RedisConnection进行了封装,它提供了连接管理,序列化等功能,它对Redis的交互进行了更高层次的抽象。

    key类型操作

    ValueOperations Redis String/Value 操作
    ListOperations Redis List 操作
    SetOperations Redis Set 操作
    ZSetOperations Redis Sort Set 操作
    HashOperations Redis Hash 操作

    value约束操作

    BoundValueOperations Redis String/Value key 约束
    BoundListOperations Redis List key 约束
    BoundSetOperations Redis Set key 约束
    BoundZSetOperations Redis Sort Set key 约束
    BoundHashOperations Redis Hash key 约束
  5. 创建Springboot项目

  6. 引入相关依赖

    <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    
  7. Springboot相关配置

    server:port: 8989
    spring:redis:database: 0               #连接redis的哪个库host: 192.168.132.16      #主机ipport: 7000                  #端口号
    
  8. 自动注入

    @Autowired
    private RedisTemplate redisTemplate;@Autowired
    private StringRedisTemplate stringRedisTemplate; #对String类型良好的支持[推荐使用]
    
  9. 测试redisTemplate

    4.1 简单的String操作

    4.2 简单的List操作

    4.3 简单的Set操作

    4.4 简单的ZSet操作

    4.5 简单的Hash操作

  10. 注意

    ​ RedisTemplate和StringRedisTemplate,不同之处在于StringRedisTemplate的Key-Value序列化使用的是StringRedisSerializer, RedisTemplate对象是默认使用JdkSerializationRedisSerializer实现

    ​ 使用StringRedisTemplate操作Redis之后的结果是友好的

18.Redis实现mybatis的缓存
# 什么是缓存缓存是计算机内存里的一段数据
# 缓存数据的特点由于缓存数据在内存中 所以读写缓存的速度非常的快
# 为什么项目中要使用缓存1.在项目中添加缓存可以在一定程度上减轻数据库的压力2.可以提高现有网站中的查询效率 加快网站的响应速度
# 项目中是否所有的数据都要使用缓存否  加入缓存的数据: 查询比较多 增删改比较少
# 在现有的项目中如何应用缓存a.借助于mybatis自身提供的缓存技术开启缓存: 在指定模块的mapper.xml中加入如下配置即可:<!-- 在mapper文件中开启缓存 --><cache/>#注意:放入缓存中的对象必须实现对象序列化接口
# mybatis自身缓存的缺点a.自身实现缓存,缓存的数据会占用一定应用服务器内存 导致应用服务处理请求的速度可能变慢这种缓存也成为本地缓存b.本地缓存在集群架构下不能实现缓存共享
# 解决本地缓存存在的问题可以实现分布式缓存服务器 redis
1.什么样的数据适合添加缓存

2.Redis实现mybatis缓存机制步骤
1.导入jar<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>
2.现有项目中如何使用redis作为分布式缓存实现a.在当前项目实现mybatis提供cache接口 public class 实现类 implements Cache(接口)b.使用自定义cache<cache type="自定义cache全限定名"/>
3.创建工具类,通过自定义的工厂工具类获取StringRedisTemplate / RedisTemplate
4.引用序列化工具类,用于SpringRedisTemplate转化获取值的类型
5.要想使用RedisTemplate实现缓存更友好展示,需要改变本身的序列化方式为SpringRedisTemplate的序列化方式
3.自定义工厂
package com.xkdgx.util;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/*** ApplicationContextUtils class** @author L-JiaHui* @date 2020/3/13*/
@Component /**当前类交由spring工厂管理*/
public class ApplicationContextUtils implements ApplicationContextAware {private static ApplicationContext applicationContext;/**获取当前的spring工厂*/@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}/**根据id获取对应的bean*/public static Object getBean(String id){Object bean = applicationContext.getBean(id);return bean;}/**根据类型获取对应的bean*/public static Object getBean(Class clazz){Object bean = applicationContext.getBean(clazz);return bean;}/**根据id+类型获取对应的bean*/public static Object getBean(String id,Class clazz){Object bean = applicationContext.getBean(id, clazz);return bean;}
}
4.序列化工具类(直接拿来用)
package com.xkdgx.util;
import java.io.*;
public class SerializeUtils {//序列化对象为字符串  其它类型--->转化为Stringpublic static String serialize(Object obj)  {try {ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();ObjectOutputStream objectOutputStream;objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);objectOutputStream.writeObject(obj);String string = byteArrayOutputStream.toString("ISO-8859-1");objectOutputStream.close();byteArrayOutputStream.close();return string;} catch (IOException e) {e.printStackTrace();}return null;}//反序列化为对象   String--->其它类型public static Object serializeToObject(String str){try {ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(str.getBytes("ISO-8859-1"));ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);Object object = objectInputStream.readObject();objectInputStream.close();byteArrayInputStream.close();return object;} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}return null;}
}
5.自定义实现类(使用SpringRedisTemplate—缓存)需要引用序列化工具类
package com.xkdgx.controller;
import com.xkdgx.util.ApplicationContextUtils;
import com.xkdgx.util.SerializeUtils;
import org.apache.ibatis.cache.Cache;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import java.util.concurrent.locks.ReadWriteLock;/***  RedisCache1 class** @author L-JiaHuui* @date 2020/3/13* */
public class RedisCache1 implements Cache {/***  注意:*      1.必须提供有参构造方法且有一个String id 的参数*      2. id:当前mapper.xml的namespace*      3.getId 返回的就是该id* */private String id;/**有参构造*/public RedisCache1(String id) {this.id = id;}/**返回当前的namespace*/@Overridepublic String getId() {return id;}/***  添加缓存:*      参数1:key     参数2:value*      添加缓存需要注入StringRedisTemplate,由于当前类是交由mybatis实例化,*      所以需要自定义工具类从当前的工厂中获取到StringRedisTemplate* */@Overridepublic void putObject(Object key, Object value) {/**获取StringRedisTemplate*/StringRedisTemplate stringRedisTemplate = (StringRedisTemplate) ApplicationContextUtils.getBean(StringRedisTemplate.class);/**StringRedisTemplate操作hash*/HashOperations<String, Object, Object> hash = stringRedisTemplate.opsForHash();/***   StringRedisTemplate:*   key-value  必须都为String*   value 可能为---> 对象、集合、地址*   将查询到的值转化为字符串(使用序列化工具类将其序列化)* */String val = SerializeUtils.serialize(value);/**插入值*/hash.put(id,key.toString(),val);}/**取出缓存*/@Overridepublic Object getObject(Object key) {/**获取StringRedisTemplate*/StringRedisTemplate stringRedisTemplate = (StringRedisTemplate) ApplicationContextUtils.getBean(StringRedisTemplate.class);/**StringRedisTemplate操作hash*/HashOperations<String, Object, Object> hash = stringRedisTemplate.opsForHash();/***  在进行取值之前先进性判断*  查询缓存:*      有缓存:返回缓存中的值*      无缓存:进入添加缓存,调用添加缓存的方法,去数据库查数据,添加缓存   return null* *//**判断大键(id)和map集合中的小键(key.toString)是否存在*/if (hash.hasKey(id,key.toString())){/**根据大键和小键拿到值(拿到的值是String类型的 在添加时进行了序列化)*/String val = (String) hash.get(id, key.toString());/**将拿到的值进行反序列化,转化为原有的类型,进行返回*/Object o = SerializeUtils.serializeToObject(val);return o;}return null;}@Overridepublic Object removeObject(Object key) {return null;}/**清空缓存*/@Overridepublic void clear() {/**获取StringRedisTemplate*/StringRedisTemplate stringRedisTemplate = (StringRedisTemplate) ApplicationContextUtils.getBean(StringRedisTemplate.class);/**根据大键(id)进行删除,实现清空缓存*/stringRedisTemplate.delete(id);}@Overridepublic int getSize() {return 0;}//Redis单线程不需要@Overridepublic ReadWriteLock getReadWriteLock() {return null;}
}
6.自定义实现类(使用RedisTemplate—缓存)
package com.xkdgx.controller;
import com.xkdgx.util.ApplicationContextUtils;
import org.apache.ibatis.cache.Cache;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.util.concurrent.locks.ReadWriteLock;
/***  RedisCache2 class** @author L-JiaHuui* @date 2020/3/13* */
public class RedisCache2 implements Cache {/***  注意:*      1.必须提供有参构造方法且有一个String id 的参数*      2. id:当前mapper.xml的namespace*      3.getId 返回的就是该id* */private String id;/**有参构造*/public RedisCache2(String id) {this.id = id;}/**返回当前的namespace*/@Overridepublic String getId() {return id;}/***  添加缓存:*      参数1:key     参数2:value*      添加缓存需要注入RedisTemplate,由于当前类是交由mybatis实例化,* */@Overridepublic void putObject(Object key, Object value) {/**获取RedisTemplate*/RedisTemplate redisTemplate = (RedisTemplate) ApplicationContextUtils.getBean("redisTemplate");/**将RedisTemplate的序列化方式JdkSerializationRedisSerializer改为* StringRedisTemplate的Key-Value序列化,是展示更加友好* */StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();redisTemplate.setKeySerializer(stringRedisSerializer);/**RedisTemplate操作hash*/HashOperations hash = redisTemplate.opsForHash();hash.put(id,key.toString(),value);}/**取出缓存*/@Overridepublic Object getObject(Object key) {/**获取RedisTemplate*/RedisTemplate redisTemplate = (RedisTemplate) ApplicationContextUtils.getBean("redisTemplate");/**改变RedisTemplate的序列化方式*/StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();redisTemplate.setKeySerializer(stringRedisSerializer);/**RedisTemplate操作hash*/HashOperations hash = redisTemplate.opsForHash();Object o = hash.get(id, key.toString());return o;}@Overridepublic Object removeObject(Object key) {return null;}/**清空缓存*/@Overridepublic void clear() {/**获取RedisTemplate*/RedisTemplate redisTemplate = (RedisTemplate) ApplicationContextUtils.getBean("redisTemplate");/**改变RedisTemplate的序列化方式*/StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();redisTemplate.setKeySerializer(stringRedisSerializer);/**删除大键(id)*/redisTemplate.delete(id);}@Overridepublic int getSize() {return 0;}//Redis单线程不需要@Overridepublic ReadWriteLock getReadWriteLock() {return null;}
}
19.缓存存在的问题
# 缓存击穿缓存穿透,是指查询一个数据库一定不存在的数据.正常的使用缓存流程大致是,数据查询先进行缓存查询,如果key不存在或者key已经过期,再对数据库进行查询,并把查询到的对象,放进缓存.如果数据库查询对象为空,则不放进缓存.
解决方案:a.查到的数据即使为空,也添加缓存(并设置较短的过期时间)b.使用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层数据库的查询压力.
# 布隆过滤器(Bloom Filter)本质上布隆过滤器是一种数据结构,比较巧妙的概率性数据结构
特点是:高效的插入和查询,可以用来告诉你"某样东西一定不存在或者可能存在"
# 缓存雪崩缓存雪崩,是指在某一个时间段,缓存集中过期失效.
解决方案:a.缓存永不过期b.设置不同的过期时间,让缓存失效的时间点尽量均匀c.缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量.比如对某个key只允许一个线程查询数据和写缓存,其他线程等待.
20.Redis集群
Redis在3.0后开始支持Cluster(模式)模式,目前redis的集群支持节点的自动发现,
支持slave-master选举和容错,支持在线分片(sharding shard)等特性
选举和容错: 主节点挂掉之后,选举一个从节点代替主节点
分片:      把数据拆分成n多份,放在每一个机器上
  1. Redis集群架构图
  2. Redis的集群细节
1.所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.
2.节点的fail是通过集群中超过半数的节点检测失效时才生效.  (一般搭建的集群是奇数个)
3.客户端与redis节点直连,不需要中间proxy(代理)层.客户端不需要连接集群所有节点,连接集群中任意一个可用节点即可
4.redis cluster把所有的物理节点映射到slot[0-16383]cluster 管理 node 管理 solt 管理 数据   (解决单点压力,分向不同的node)
solt: 槽Redis 集群没有并使用传统的一致性哈希来分配数据,而是采用另外一种叫做哈希槽 (hash slot)的方式来分配的。redis cluster 默认分配了 16384 个slot,当我们set一个key 时,会用CRC16算法来取模得到所属的slot,然后将这个key 分到哈希槽区间的节点上,具体算法就是:CRC16(key) % 16384。(为什么是16384,选取了16384是因为crc16会输出16bit的结果,可以看作是一个分布在0-2^16-1之间的数,redis的作者测试发现这个数对2^14求模的会将key在0-2^14-1之间分布得很均匀,因此选了这个值。)在构建redis cluster集群时,master必须大于等于3,否则会创建失败。并且,当集群中存活的master节点数小于总节点数的一半的话,集群就无法提供服务了。例:我们有三个master节点A、B、C,采用哈希槽 (hash slot)的方式来分配16384个slot 的话,它们三个节点分别承担的slot 区间是:节点A:0 ~ 5460节点B:5461 ~ 10922节点C:10923 ~ 16383
节点在收到读写请求时,会根据CRC16(key) % 16384算出的槽号去查是否指向自己,如果是则进行处理,如果不是,则返回moved错误,moved错误携带正确的节点IP和端口号返回客户端并指引其转向执行,而后客户端每次关于该key都会去moved返回的节点执行。当节点的key正在迁移的时候,收到关于该key的请求,那么节点会返回ask错误,并但会正确的节点ip和端口号给客户端去执行。但是这个转向只对本次请求有效,后面关于该key的请求还是会发送到目前正在处理key迁移的节点,直到key迁移完毕并发送广播通知。
当有新节点D加入时,redis cluster的这种做法是从各个节点的前面各拿取一部分slot到D上。会变成下面这样:节点A:1364 ~ 5460节点B:6826 ~ 10922节点C:12287 ~ 16383节点D:0 ~ 1364, 5461 ~ 6826, 10923 ~ 12287
删除节点也是类似,数据会均匀的迁移到剩余节点上,迁移完成后就可以删除这个节点了。
  1. redis容错架构图

  2. 容错的细节

    1.如果半数以上master节点与master节点通信超时(cluster-node-timeout),认为当前master节点挂掉
    2.收到((error) CLUSTERDOWN The cluster is down)错误,整个集群不可用(cluster_state:fail),所有对集群的操作做都不可用#注意:如果集群任意master挂掉,且当前master没有slave.集群进入fail状态也可以理解成进群的slot映射[0-16383]不完成时进入fail状态.
    
  3. redis集群搭建

    #注意 : 1.    判断一个是集群中的节点是否可用,是集群中的所用主节点选举过程,如果半数以上的节点认为当前节点挂掉,那么当前节点就是挂掉了,所以搭建redis集群时建议节点数最好为奇数.2.  搭建集群至少需要三个主节点,三个从节点,至少需要6个节点
    
   1.准备至少六台机器port 7000 - 70052.修改六台机器的配置文件cluster-enabled  yes                    //开启集群模式       cluster-config-file  nodes-.conf        //集群节点配置文件    cluster-node-timeout  15000          //集群节点超时时间(默认 15秒)appendonly  yes                       //开启AOF持久化3.构建集群./redis-server /root/7000/redis.conf./redis-server /root/7001/redis.conf./redis-server /root/7002/redis.conf./redis-server /root/7003/redis.conf./redis-server /root/7004/redis.conf./redis-server /root/7005/redis.conf./redis-cli --cluster create 192.168.244.15:7000 192.168.244.15:7001 192.168.244.15:7002 192.168.244.15:7003 192.168.244.15:7004 192.168.244.15:7005 --cluster-replicas 1注意:修改成自己定义的端口号

4.   输入yes后集群确定搭建,输入其它命令不创建集群

5.客户端操作集群a)集群中的节点都是平等的,连接集群中的任意节点即可./redis-cli -p 任意port -c-c: 集群形式
6.查看接群节点的状态a)使用./redis-cli --cluster check ip:port 查看集群中节点的详细 ./redis-cli --cluster check 192.168.64.10:任意可用port

7.节点状态说明#主节点 :√ 主节点存在hash slots,且主节点的hash slots 没有交叉√ 主节点不能删除√ 一个主节点可以有多个从节点√ 主节点宕机时多个副本之间自动选举主节点#从节点 :√ 从节点没有hash slots√ 从节点可以删除√ 从节点不负责数据的写,只负责数据的同步√ 从节点对应的主节点宕机,该从节点会变为主节点
  1. 集群节点的操作

    1.向集群中添加一个主节点./redis-cli --cluster add-node 192.168.132.16:7006 192.168.132.16:7005
    

  参数说明i. 第一个参数是新节点的地址,ii. 第二个参数是任意一个已经存在的节点的IP和端口#注意 : 1.该节点必须以集群模式启动2.默认情况下该节点就是以master节点形式添加,但是该节点没有hashslots

2.向集群中添加副本节点./redis-cli --cluster add-node 192.168.132.16:7007 192.168.132.16:7006 --cluster-slave

  参数说明 : add-node 添加从节点参数一:新的从节点参数二:集群中的任意节点#注意:当添加副本节点时没有指定主节点,redis会随机给副本节点较少的主节点添加当前副本节点
---~~~txt
3.为某个指定主节点添加从节点./redis-cli --cluster add-node 192.168.244.15:7007 192.168.244.15:7000 --cluster-slave --cluster-master-id 747e1871ea74103e4a6dd0137dd5a222270462b0

  参数说明 :参数一: 新添加的从节点参数二: 集群中的任意节点--cluster-master-id 主节点id

4.从集群中删除副本节点./redis-cli --cluster del-node 192.168.244.15:7005 17a31e662ff7b1854da2b3c8e62088814b4a884c
   参数说明:参数一是任意一个节点的地址 参数二是想要删除的节点id#注意 :被删除的节点必须是从节点或没有被分配hash slots的节点


5.节点的从新分片a)集群节点(hash slots)的从新分配(reshard)使用 ./redis-cli --cluster reshard 192.168.132.16:7006#说明 : 需要指定集群中其中一个节点的地址就会自动找到集群中的其他主节点。

     b)为哪个主节点分配hash slots

21.后台连接Redis集群
  1. Jedis操作Redis

​ 注意:

​ 避免redis某个节点宕机的问题,一般会配置多个连接

​ 集群模式下不能再切换库,只能用0号库

​ flushall, flushdb 都不能用

  1. SpringData操作Redis

redis的基本操作And数据持久化方式以及redis实现mybatis缓存相关推荐

  1. Redis(2)---数据持久化

    Redis(2)---数据持久化 原文:Redis(2)---数据持久化 数据持久化 Redis有两种持久化的方式:快照(RDB文件)和追加式文件(AOF文件) (1)RDB持久化方式是在一个特定的间 ...

  2. 老司机带你玩转面试(1):缓存中间件 Redis 基础知识以及数据持久化

    引言 今天周末,我在家坐着掐指一算,马上又要到一年一度的金九银十招聘季了,国内今年上半年受到 YQ 冲击,金三银四泡汤了,这就直接导致很多今年毕业的同学会和明年毕业的同学一起参加今年下半年的秋招,这个 ...

  3. iOS 数据持久化方式 - 归档 反归档

    所谓归档:将复杂对象转化为NSData类型数据(复杂-->归档-->NSData--->WriteToFile) 注意:归档是将对象转化为数据字节,以文件的形式存储在磁盘上, 所谓反 ...

  4. Redis详解(redis线程模式、数据持久化机制、主从复制、缓存穿透、缓存击穿等)

    一.redis概述 redis主要用作数据库.缓存和消息中间件, 支持多种语言, 是基于内存的key-value数据结构存储系统. redis支持数据的持久化, 可以将内存中的数据保存在磁盘中, 重启 ...

  5. 四种数据持久化方式(上) :属性列表与归档解档

    iOS中的永久存储,也就是在关机重新启动设备,或者关闭应用时,不会丢失数据.在实际开发应用时,往往需要持久存储数据的,这样用户才能在对应用进行操作后,再次启动能看到自己更改的结果与痕迹. iOS开发中 ...

  6. Redis常见面试题6 -- 持久化方式之AOF以及混合模式

    持久化方式之AOF以及混合模式 目前主流Redis持久化:

  7. Redis高并发5-redis数据持久化之企业应用

    到这里为止,其实还是停留在简单学习知识的程度,学会了redis的持久化的原理和操作,但是在企业中,持久化到底是怎么去用得呢? 企业级的数据备份和各种灾难下的数据恢复,是怎么做得呢? 1.企业级的持久化 ...

  8. redis中几种数据存储方式的比较

    2019独角兽企业重金招聘Python工程师标准>>> 这是慕课网一门课程的提问,有一个回答很不错,我就摘抄过来了.链接 原问题: 为什么不用redis的hash来存储对象? 二进制 ...

  9. Redis常见面试题5 -- 持久化方式之RDB(快照模式)

    redis.conf文件 保存快照策略

最新文章

  1. 一个仿微信朋友圈的图片查看框架 - PhotoViewer
  2. Android配置启动界面:Activity基本使用
  3. 脚本语言php是什么意思,php是什么脚本语言
  4. jenkins Auth fail验证失败
  5. Python爬虫之xpath的详细使用(爬虫)
  6. 特征工程系列之自动化特征提取器
  7. 【心得】centos 去除屏幕保护
  8. 2个相同的 stm32 can通讯不成功_一文读懂,基于 STM32 和 CAN 总线的温度监控系统的设计方法...
  9. ms office excel2013教程 - 从网站加载数据
  10. Cutting Sticks
  11. 中大计算机考研复试刷人太狠,来!看看这些院校复试刷人刷的有多厉害
  12. 《大道至简》的幕后故事(4):“愚公移山记”军事地理篇
  13. 现货白银报价系统与软件
  14. ELasticSearch——head插件的安装和基本使用
  15. nport串口服务器原理,串口服务器Nport5130/5430配置使用说明
  16. Intellij+Maven+SpringBoot+Mybatis+Oracle整合教程
  17. OpenGL开发时,fatal error C1083: 无法打开包括文件:“gl\glut.h”: No such file or directory...
  18. Java 进阶(三)动态代理
  19. GC一些长时间停顿问题排查及解决办法
  20. 微信返回按钮ios和安卓兼容最终方案

热门文章

  1. 用R语言绘制ROC曲线
  2. Android KeyCode列表 input keyevent XXX
  3. aardio - 调用Python库下载蓝奏盘文件
  4. 如何自己手动修改win10磁贴背景颜色?
  5. matlab设置图片背景透明_Matlab ---- 有透明度的png图像的显示与图层叠加方法
  6. Java 如何查询当前项目Spring和SpringBoot的版本号
  7. 服务器有必要更新主板芯片组吗,芯片组驱动要不要更新_芯片组驱动卸载了会怎么样...
  8. 房地产行业分销渠道管理系统:促进渠道商内外沟通,提升成交效率
  9. Ubuntu中Cairo Dock内天气预报地理位置的设置
  10. 分布式锁的实现【转载】