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

avatar
作者
猴君
阅读量:0
  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<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);     @Autowired     public 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));     } }

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!