{{π型人才培养计划}}Redis 缓存
2021/6/4 2:21:00
本文主要是介绍{{π型人才培养计划}}Redis 缓存,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
Redis 缓存
1.为什么使用缓存
缓存就是在内存中存储的数据备份,当数据没有发生本质变化的时候,我们避免数据的查询操作直接连接数据库,而是去内容中读取数据,这样就大大降低了数据库的读写次数,而且从内存中读数据的速度要比从数据库查询要快很多,极大的提升了应用程序的性能和效率,特别是数据查询方面
2.使用缓存存在的问题
2.1缓存穿透
概念:
是指查询数据库中一定不存在的数据。先在缓存中查询,如果key不存在或者key已经过期,再对数据库进行查询,并把查询到的对象,放进缓存中。如果数据库查询对象空,则不放进缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,造成缓存穿透。
解决办法:
1.布隆过滤
最常见的则是采用布隆过滤器,将所有可能存在的数据到一个足够大的bitmap中,对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,一个一定不存在的数据会被bitmap拦截掉从而避免了对底层存储系统的查询压力。
2.强而有力
访问key未在DB查询到的空值写进缓存,设置较短过期时间
2.2缓存雪崩
概念:
大量的key设置了相同的过期时间,导致在缓存在同一时刻全部失效,造成瞬时DB请求量大、压力骤 增,引起雪崩。
解决办法:
可以给缓存设置过期时间时加上一个随机值时间,使得每个key的过期时间分布开来,不会集中在同一时 刻失效。
2.3缓存的击穿
概念:
一个存在的key,在缓存过期的一刻,同时有大量的请求,这些请求都会击穿到DB,造成瞬时DB请求量 大、压力骤增。
解决办法:
“永远不过期”:
这里的“永远不过期”包含两层意思: (1) 从redis上看,确实没有设置过期时间,这就保证了,不会出现热点key过期问题,也就是“物理”不过期。 (2) 从功能上看,如果不过期,那不就成静态的了吗?所以我们把过期时间存在key对应的value里,如果发现要过期了,通过一个后台的异步线程进行缓存的构建,也就是“逻辑”过期 从实战看,这种方法对于性能非常友好,唯一不足的就是构建缓存时候,其余线程(非构建缓存的线程)可能访问的是老数据,但是对于一般的互联网功能来说这个还是可以忍受。
3.mybatis一级,二级缓存
一级缓存:
一级缓存基于sqlSession默认开启,在操作数据库时需要构造SqlSession对象,在对象中有一个HashMap 用于存储缓存数据。不同的SqlSession之间的缓存数据区域是互相不影响的
二级缓存:
二级缓存的作用域是mapper的同一个namespace。不同的sqlSession两次执行相同的namespace下的s ql语句,且向sql中传递的参数也相同,即最终执行相同的sql语句,则第一次执行完毕会将数据库中查询的数 据写到缓存,第二次查询会从缓存中获取数据,不再去底层数据库查询,从而提高效率,多表联合查询时会造 成脏读的情况
4.redis
4.1简介
Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。
Redis 与其他 key - value 缓存产品有以下三个特点:
- Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
- Redis不仅仅支持简单的key-value类型的数据,同时还提供string,list,set,zset,hash等数据结构的存储。
- Redis支持数据的备份,即master-slave模式的数据备份。
4.2Redis的5种数据类型及其适用场景
(1)String:可以包含任何数据,比如jpg图片或者序列化的对象.。
(2)List:链表(双向链表),增删快,提供了操作某一段元素的API。适用于:最新消息排行等功能;消息队列。
(3)Set:集合。哈希表实现,元素不重复,为集合提供了求交集、并集、差集等操作。适用于:共同好友;利 用唯一性,统计访问网站的所有独立ip;好友推荐时,根据tag求交集,大于某个阈值就可以推荐。
(4)Hash 键值对集合,即编程语言中的Map类型。适合存储对象,并且可以像数据库中update一个属 性一样只修改某一项属性值。适用于:存储、读取、修改用户属性。
(5)Sorted Set:有序集合。将Set中的元素增加一个权重参数score,元素按score有序排列。数据插入集合时, 已经进行天然排序。适用于:排行榜;带权重的消息队列。
4.3优势
- 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
- 丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
- 原子 – Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性.
- 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。
4.4其他key-value存储有什么不同?
- Redis有着更为复杂的数据结构并且提供对他们的原子性操作,这是一个不同于其他数据库的进化路径。Redis的数据类型都是基于基本数据结构的同时对程序员透明,无需进行额外的抽象。
- Redis运行在内存中但是可以持久化到磁盘,所以在对不同数据集进行高速读写时需要权衡内存,因为数据量不能大于硬件内存。在内存数据库方面的另一个优点是,相比在磁盘上相同的复杂的数据结构,在内存中操作起来非常简单,这样Redis可以做很多内部复杂性很强的事情。同时,在磁盘格式方面他们是紧凑的以追加的方式产生的,因为他们并不需要进行随机访问。
5.redis实现缓存
5.1redis实现mybatis的二级缓存
用redis做mybatis的缓存,只能于mybatis
5.2.基于aop,实现通用的缓存
aop的机制:
AOP是Spring框架面向切面的编程思想,AOP采用一种称为“横切”的技术,将涉及多业务流程的通用功能 抽取并单独封装,形成独立的切面,在合适的时机将这些切面横向切入到业务流程指定的位置中。
6.Redis的安装
1. 安装gcc运行环境 yum -y install gcc 或手动导入安装 2. 上传redis的资料包 在CRT中 alt+p , 直接拖进 3. 解压redis的压缩包 tar -zxvf xxx.zip 4. 进入redis包执行指令 make 5. 编译完成之后安装redis make install PREFIX=/usr/redis 6. 启动redis ./redis-server /root/redis-4.0.9/redis.conf 7. 使用redis的客户端连接redis服务 ./redis-cli –p 6379 8. 需要后台链接redis vi redis-4.0.9/redis.conf 9. 关闭redis ./redis-cli –p 6379 shutdown
10. 启动redis的服务 ./redis-server /root/redis-4.0.9/redis.conf
9.Redis缓存后台实现
-
思路
-
需要的jar
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
-
实现redis缓存
3.1基于切方法
@Configuration @Aspect//声明当前类是一个切面供容器读取 public class RedisCache { @Autowired private RedisTemplate redisTemplate; @Autowired private StringRedisTemplate stringRedisTemplate; @Around("execution(* com.baizhi.service.*.select*(..))") public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { RedisSerializer stringSerializer = new StringRedisSerializer(); redisTemplate.setKeySerializer(stringSerializer); redisTemplate.setHashKeySerializer(stringSerializer); StringBuilder sb = new StringBuilder(); //获取类名 String className = proceedingJoinPoint.getTarget().getClass().getName(); sb.append(className); //获取方法名 String methodName = proceedingJoinPoint.getSignature().getName(); sb.append(methodName); //获取所有的参数 Object[] args = proceedingJoinPoint.getArgs(); for (Object arg : args) { sb.append(arg); } String s = sb.toString(); ValueOperations valueOperations = redisTemplate.opsForValue(); Object result = null; if(redisTemplate.hasKey(s)){ result = valueOperations.get(s); }else{ result = proceedingJoinPoint.proceed(); valueOperations.set(s,result); } return result; } @After("execution(* com.baizhi.service.*.delete*(..))") public void after(JoinPoint joinPoint){ Set<String> keys = stringRedisTemplate.keys("*"); for (String key : keys) { stringRedisTemplate.delete(key); } }
注意:
发现key值出现 \xac\xed\x00\x05t\x00\tb,redisTemplate 默认的序列化方式为 jdkSerializeable, StringRedisTemplate的默认序列化方式为StringRedisSerializer
3.2基于切自定义注解
1.自定义注解 //添加缓存 @Target(ElementType.METHOD)//声明注解使用的位置 @Retention(RetentionPolicy.RUNTIME) public @interface SaveRedisCache { //可以加属性 //public String/int/... value(); } //移除缓存 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface RemoveRedisCache { //可以加属性 //public String/int/... value(); } @Configuration//当前类为配置类 @Aspect//作用是把当前类标识为一个切面供容器读取 public class RedisCache { @Autowired private RedisTemplate redisTemplate; @Around("@annotation(com.baizhi.annotation.SaveRedisCache)") public Object arround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { StringBuilder sb = new StringBuilder(); //获取类名 String className = proceedingJoinPoint.getTarget().getClass().getName(); //获取方法名 String methodName = proceedingJoinPoint.getSignature().getName(); sb.append(methodName); //获取所有的参数 Object[] args = proceedingJoinPoint.getArgs(); for (Object arg : args) { sb.append(arg); } String s = sb.toString(); HashOperations hashOperations = redisTemplate.opsForHash(); Boolean aBoolean = redisTemplate.hasKey(className); Object result = null; if(aBoolean){ result = hashOperations.get(className,s); }else { result = proceedingJoinPoint.proceed(); HashMap<String, Object> map = new HashMap<>(); map.put(s, result); hashOperations.putAll(className, map); redisTemplate.expire(className,10, TimeUnit.SECONDS); } return result; }
2. 写的操作需要清除缓存
@After("@annotation(com.baizhi.annotation.RemoveRedisCache)") public void after(JoinPoint joinPoint){ String className = joinPoint.getTarget().getClass().getName(); redisTemplate.delete(className); }
return result;
}
2. 写的操作需要清除缓存 ~~~java @After("@annotation(com.baizhi.annotation.RemoveRedisCache)") public void after(JoinPoint joinPoint){ String className = joinPoint.getTarget().getClass().getName(); redisTemplate.delete(className); }
这篇关于{{π型人才培养计划}}Redis 缓存的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-18Redis安装入门:新手必读指南
- 2024-11-08阿里云Redis项目实战入门教程
- 2024-11-08阿里云Redis资料:新手入门与初级使用指南
- 2024-11-08阿里云Redis教程:新手入门及实用指南
- 2024-11-07阿里云Redis学习入门:新手必读指南
- 2024-11-07阿里云Redis学习入门:从零开始的操作指南
- 2024-11-07阿里云Redis学习:初学者指南
- 2024-11-06阿里云Redis入门教程:轻松搭建与使用指南
- 2024-11-02Redis项目实战:新手入门教程
- 2024-10-22Redis入门教程:轻松掌握数据存储与操作