当前位置: 首页 > news >正文

mybatisplus布隆过滤器解决缓存穿透

  1. 首先自定义一个mybatis的拦截器,实现Interceptor接口。
  2. 重写intercept方法。
  3. 在intercept方法里面通过invocation获取到QueryWrapper。
  4. 通过QueryWrapper的getParamNameValuePairs方法获取查询条件参数。
  5. 注意在Executor阶段,出现getParamNameValuePairs为空的情况,需要显示调用一次getCustomSqlSegment后,参数才会被填充到 paramNameValuePairs 中。
  6. 然后使用guava库,实现布隆过滤器。
  7. 自定义一个配置类,在配置类里面set方法注入Mapper,通过Mapper一次查询所有key添加到布隆过滤器。
  8. 之后的每次查询都会先使用布隆过滤器判断是否存在,否则直接返回。
  9. 这里我返回的是ArrayList<?>,?是一个实体类对应一张mysql表。
  10. 返回的是ArrayList<?>集合还需要创建一个?实例。
  11. 如果key存在,在判断是否命中缓存,使用的redis做缓存
  12. redis缓存的数据,必须序列化成字符串或者字节数组
    package com.example.Interceptor;
    import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    import com.example.config.MyConfiguration;
    import com.example.domain.Emp;
    import com.example.util.CacheKeyGenerator;
    import org.apache.ibatis.executor.Executor;
    import org.apache.ibatis.mapping.MappedStatement;
    import org.apache.ibatis.plugin.*;
    import org.apache.ibatis.session.ResultHandler;
    import org.apache.ibatis.session.RowBounds;
    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisPool;
    import redis.clients.jedis.JedisPoolConfig;
    import java.io.*;
    import java.util.ArrayList;
    import java.util.Map;
    import java.util.Properties;@Intercepts({@Signature(type = Executor.class,method = "query",args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}
    )})
    public class CacheInterceptor implements Interceptor {@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {}public static byte[] serialize(Object obj) throws IOException {ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);objectOutputStream.writeObject(obj);return byteArrayOutputStream.toByteArray();}private static JedisPool pool;static {System.out.println("static....");// 配置连接池JedisPoolConfig poolConfig = new JedisPoolConfig();poolConfig.setMaxTotal(30); // 最大连接数poolConfig.setMaxIdle(10);  // 最大空闲连接数poolConfig.setMinIdle(5);   // 最小空闲连接数poolConfig.setTestOnBorrow(true); // 借用连接时进行连接测试poolConfig.setTestOnReturn(true); // 归还连接时进行连接测试poolConfig.setTestWhileIdle(true); // 空闲时进行连接测试poolConfig.setMinEvictableIdleTimeMillis(60000); // 逐出连接的最小空闲时间poolConfig.setTimeBetweenEvictionRunsMillis(30000); // 逐出扫描的时间间隔// 创建连接池pool = new JedisPool(poolConfig, "localhost", 6379);}@Overridepublic Object intercept(Invocation invocation) throws Throwable {System.out.println("intercept....");Map<?, ?> arg = ( Map<?, ?>) invocation.getArgs()[1];System.out.println(arg);Map<String, Object> paramNameValuePairs=null;Long id=null;for (Object entry : arg.values()) {if(entry!=null) {QueryWrapper<?> queryWrapper_emp = (QueryWrapper<?>) entry;System.out.println(queryWrapper_emp.getCustomSqlSegment());paramNameValuePairs = queryWrapper_emp.getParamNameValuePairs();System.out.println(paramNameValuePairs);id = (Long) paramNameValuePairs.get("MPGENVAL1");System.out.println(id);if(!MyConfiguration.bloomFilter.mightContain(Math.toIntExact(id))){System.out.println("不存在");ArrayList<Emp> objects = new ArrayList<>();objects.add(new Emp());return objects;}System.out.println("paramNameValuePairs=" + paramNameValuePairs);}break;}String generateKey = CacheKeyGenerator.generateKey(paramNameValuePairs);Jedis jedis=null;try {jedis= pool.getResource();byte[] generateKeybytes = jedis.get(generateKey.getBytes());if(generateKeybytes!=null){Object deserialize = deserialize(generateKeybytes);System.out.println("命中");return deserialize;}else{System.out.println("未命中");Object proceed = invocation.proceed();jedis.set(generateKey.getBytes(),serialize(proceed));return proceed;}}catch (Exception e){e.printStackTrace();}finally {jedis.close();}return null;}// 反序列化对象public static Object deserialize(byte[] bytes) throws IOException, ClassNotFoundException {ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);return objectInputStream.readObject();}
    }
    
    package com.example.config;import com.example.domain.Emp;
    import com.example.mapper.EmpMapper;
    import com.google.common.hash.BloomFilter;
    import com.google.common.hash.Funnels;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Configuration;import java.util.Iterator;
    import java.util.List;@Configuration
    public class MyConfiguration {public static BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(), 10000, 0.01);@Autowiredpublic void setEmpMapper(EmpMapper empMapper){List<Emp> emps = empMapper.selectList(null);Iterator<Emp> iterator = emps.iterator();while (iterator.hasNext()){Emp next = iterator.next();bloomFilter.put(Math.toIntExact(next.getId()));}System.out.println(bloomFilter.mightContain(3214044));System.out.println(bloomFilter.mightContain(7213478));}
    }

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • <数据集>棉花识别数据集<目标检测>
  • FPGA:我的零基础学习路线(2022秋招已上岸)持续更新中~
  • asp.net mvc 三层架构开发商城系统需要前台页面代完善
  • 3千米以上音视频键鼠延长解决方案:KVM光纤延长器
  • 什么是Java并发中的锁池?
  • Redis学习[5] ——Redis过期删除和内存淘汰
  • 使用 ModelScope 本地部署图片变视频模型
  • 深入理解Java注解
  • [网鼎杯 2020 青龙组]AreUSerialz1
  • vue后台管理系统 vue3+vite+pinia+elementui+axios下
  • 接口测试框架中测试用例管理模块的优化与思考!
  • 理解ThreadLocal 变量副本,为什么不同线程的 ThreadLocalMap互不干扰
  • LSTM与GNN强强结合!全新架构带来10倍推理速度提升
  • centos7 中安装 mysql 8.x以及对数据库的管理(数据库、表的增删改查、插入删除数据)
  • Electron工作流程(2)——进程间通信
  • 【附node操作实例】redis简明入门系列—字符串类型
  • 【知识碎片】第三方登录弹窗效果
  • ES6简单总结(搭配简单的讲解和小案例)
  • JWT究竟是什么呢?
  • Linux编程学习笔记 | Linux多线程学习[2] - 线程的同步
  • php ci框架整合银盛支付
  • React as a UI Runtime(五、列表)
  • Spring Boot MyBatis配置多种数据库
  • V4L2视频输入框架概述
  • Vim 折腾记
  • 高程读书笔记 第六章 面向对象程序设计
  • 机器人开始自主学习,是人类福祉,还是定时炸弹? ...
  • 完善智慧办公建设,小熊U租获京东数千万元A+轮融资 ...
  • 昨天1024程序员节,我故意写了个死循环~
  • #!/usr/bin/python与#!/usr/bin/env python的区别
  • (floyd+补集) poj 3275
  • (创新)基于VMD-CNN-BiLSTM的电力负荷预测—代码+数据
  • (二)hibernate配置管理
  • (附源码)springboot掌上博客系统 毕业设计063131
  • (附源码)ssm高校社团管理系统 毕业设计 234162
  • (接口自动化)Python3操作MySQL数据库
  • (精确度,召回率,真阳性,假阳性)ACC、敏感性、特异性等 ROC指标
  • (七)Java对象在Hibernate持久化层的状态
  • (强烈推荐)移动端音视频从零到上手(上)
  • (四)JPA - JQPL 实现增删改查
  • (转)linux下的时间函数使用
  • .net redis定时_一场由fork引发的超时,让我们重新探讨了Redis的抖动问题
  • .net 怎么循环得到数组里的值_关于js数组
  • .NET/C# 中你可以在代码中写多个 Main 函数,然后按需要随时切换
  • .NetCore发布到IIS
  • .NET关于 跳过SSL中遇到的问题
  • @media screen 针对不同移动设备
  • [ CTF ] WriteUp- 2022年第三届“网鼎杯”网络安全大赛(朱雀组)
  • [ 物联网 ]拟合模型解决传感器数据获取中数据与实际值的误差的补偿方法
  • [AIGC] 解题神器:Python中常用的高级数据结构
  • [C#]获取指定文件夹下的所有文件名(递归)
  • [C#基础知识系列]专题十七:深入理解动态类型
  • [CISCN2019 华东南赛区]Web111
  • [docker] Docker的私有仓库部署——Harbor
  • [HackMyVM]靶场Crossbow