mybatisplus布隆过滤器解决缓存穿透
创始人
2024-11-15 02:33:05
  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 {          @Override         public Object plugin(Object target) {                 return Plugin.wrap(target, this);         }          @Override         public 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);          }         @Override         public Object intercept(Invocation invocation) throws Throwable {                 System.out.println("intercept....");                 Map arg = ( Map) invocation.getArgs()[1];                 System.out.println(arg);                 Map 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 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 bloomFilter = BloomFilter.create(Funnels.integerFunnel(), 10000, 0.01);     @Autowired     public void setEmpMapper(EmpMapper empMapper){         List emps = empMapper.selectList(null);         Iterator 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));     } }

相关内容

热门资讯

裸辞做“一人公司”,我后悔了 去年这个时候,一位以色列程序员正在东南亚旅行。他顺手把一个在脑子里转了很久的想法做成了产品,一个让任...
南京建成国内首个Pre-6G试... 4月21日,2026全球6G技术与产业生态大会在南京开幕。全息互动技术展台前,一名远在北京的工作人员...
超梵求职受邀参加“2025抖音... 超梵求职受邀参加“2025抖音巨量引擎成人教育行业生态大会”,探讨分享优质内容传播,服务万千学员。 ...
摩托罗拉Razr 2026(R... IT之家 4 月 22 日消息,摩托罗拉宣布新一代 Razr 折叠手机将于 4 月 29 日在美国发...
库克卸任,特纳斯领航:苹果新纪... 苹果首席执行官蒂姆·库克将卸任,硬件工程主管约翰·特纳斯将接任,苹果公司今天宣布此事。 库克将在夏季...