当数据量最少10w+,还需要模糊搜索,你会怎么提升性能?[实战性分析教学]

948 阅读4分钟

当数据量很大时,还需要你模糊搜索,这时的性能优化你会怎么做?

前言

最近来了一个任务,让我查询一个银行卡bin信息,可能没有做过这方面的小伙伴们可能不知道,这个卡bin信息表的数据量非常大,如果接口处理不好的话速度会非常慢。(一个接口可能会拖垮整个项目)。

在这里插入图片描述
这时候如果还是用简单的sql去查,那么你就会掉入代码的陷阱。 具体怎么办,我来教大家~
在这里插入图片描述

进入正题

任务背景

是一个非常简单的查询卡bin接口 如图:

在这里插入图片描述
传参的话会传入一个 cardNo
代表银行卡号 (在后续查询中可能会出现其他参数,固定枚举型我们不做讨论) 用来@注解 做了一个简单的长度判断和提示信息

返回信息就是查询出来的卡bin信息

问题分析

常规查询操作: 直接不管是jpa还是什么的 直接根据cardNo模糊查询即可 (其他参数不讨论) 如图:

在这里插入图片描述
但是这时候你会发现,查询结果在数据量大的时候,会非常慢。 所以直接pass,必须进行性能优化! 优化后: 我简单考虑了一下,决定使用,redis数据库来存储完整数据。 redis是Nosql型数据库,数据结构服务器,以,Key-value方式存储数据。所以数据存取速度非常快。

不了解的小伙伴可以一会去了解一下,使用方法非常简单。 方法很简单。

思路: 1.首先吧数据在启动项里面去调用,去简单的分类查一下所有的数据,然后把数据放入到redis里面去。 2.当我调用模糊查询方法时,直接做判断条件循环去从redis里取即可。

有了思路之后,我们就要开始干活了!

首先简单说一下redis怎么引入项目

简单说一下redis怎么引入 首先在项目中引入redis 在pom文件中,简单的加上依赖

 <!--redis的起步依赖-->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
  </dependency>

在application.properties指向一下自己redis的服务地址

# redis
spring.redis.host=127.0.0.1
spring.redis.port=6379

然后在想应用的地方直接注入redis操作类

@Autowired
    private RedisTemplate<Object,Object> redisTemplate;

大致的引用就完成了

代码环节

到了本文的关键,代码环节。 我会尽量简化代码的阅读量,让大家最快的方式理解我的意思,方法是千变万化的,但是思路确能复用。

首先: 1.我要存储数据放入redis 但是放入redis之前,要先引用

@Autowired
protected RedisTemplate<String, CardBinDTO> redisTemplate;

注意:redisTemplate因为泛型参数不是Object,所以需要去配置一下 创建 RedisTemplateConfig

@Component
public class RedisTemplateConfig {
    @Bean
    public RedisTemplate<String, CardBinDTO> redisCardBinVOTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, CardBinDTO> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);
        return redisTemplate;
    }
}

然后再去注入redisTemplate就可以了 继续看代码。 查询数据并放入redis代码

 /**
     * 缓存reids
     */
    @Transactional(rollbackFor = Exception.class)
    public void saveORUpdateRedisOrCardBin() {
    //一个根据条件查询卡bin的方法
        List<BankCardBin> cardBins = bankCardService.findAllByZyzhFlagAndFlag(ZyzhFlag.WITHDRAW_AND_CONSUME, CardFlag.DEBIT_CARD);
        //list循环,缓存redis,同时吧对象复制成DTO对象进行数据传输
        //设置redis生命周期,30days
        cardBins.forEach(bankCardBin ->
                redisTemplate.opsForValue().set(bankCardBin.getCardBin(), BeanCopyUtils.copyBean(bankCardBin, CardBinDTO.class), 30, TimeUnit.DAYS)
        );
    }

2.根据传入参数从Redis内返回指定数据

   @Override
    public CardBinDTO findCardBinInfo(String cardNo) {
    //模糊的查询的是cardno 也就是银行卡号,表bin字段在需求书上有规定,最长是12,最短是3,所以循环条件是i=12,i>=3
        for (int i = 12; i >= 3; i--) {
        //根据i的当前长度截取一下银号卡号
            String substring = cardNo.substring(0, i);
            //根据现有银行卡号去从redis里取值,有一条数据就返回即可
            if (redisTemplate.hasKey(substring)) {
                return redisTemplate.opsForValue().get(substring);
            }
        }
        //如果循环完没有值,则抛出异常
        throw new ServiceException(ResultCode.NOT_CARD_BINDING);
    }

到这里,方法大概就结束了,就剩下调用了。

代码和思路都很简单,希望大家看的明白!

如果大家觉得还不错,希望可以给我一个赞,非常感谢!

您的点赞是我最大的鼓励!

作者的话

互相尊重,互相进步,很感谢大家的无私精神。才能让我们中国IT越来越进步! 也非常愿意虚心听取更多大佬的意见和建议,和大家一起交流进步 我是你们的好朋友 樊亦凡

一个每天进步一点点的程序员!