分页 + 模糊查询竟然有坑?

不知道你有没有使用过Mysqllike语句,进行模糊查询?

不知道你有没有将查询结果,进行分页处理?

模糊查询,加上分页处理,会有意想不到的坑,不信我们继续往下看。

我之前提供过一个品牌查询接口,给前端品牌选择控件使用的。

当时为了性能考虑,怕前端控件因为一次性加载太多的品牌,而导致页面卡死。

因此,对品牌查询接口做了分页处理。

刚开始品牌表的数据比较少,没有出现什么问题。

后来,产品加需求了,在品牌下拉选择控件中,让用户可以输入自定义品牌。

在用户添加品牌前,需要先查一下,如果该品牌存在,则使用已有品牌。如果不存在,则新增品牌。(这里是精确匹配)

这个需求很简单,很容易实现了。

后来,产品又加需求了,需要按名称模糊查询品牌。

该功能上线后,使用了很长一段时间,也没啥问题。

突然,在不经意的某一天,这个功能却出问题了。

到底怎么回事呢?

1.案发现场

某一天下午,运营找到测试反馈一个问题说:明明品牌苏三,已经存在了,但用户输入关键字:苏三时,系统没有让用户直接选择已有品牌,而是添加了一个叫:苏三的自定义的品牌。

我过去一看,还真的有问题。

不一会儿,就定位到原因了,初步判断是分页的问题。

搜索关键字:苏三,竟然出现了好几页的数据,把我惊呆了,品牌表怎么多了这么多数据了。

我查了数据库,其实数据量并不是特别多,但有些品牌名称比较特殊,有些品牌名称是多个品牌名称拼接而成的,比如:苏三,李四 或者 苏三,李四,王五,这是一个品牌。

其实是品牌名称建的不规范导致的问题,但已经没法让运营修改品牌了,只能通过技术手段解决目前的问题。

查询第一页的数据sql:

select * from brand where name like '%苏三%' 
order by edit_date desc limit 5;

执行结果:8e9287e761447c8b0f7e7eef7f5e6251.png我们可以看到,图中并没有等于苏三这两个字的数据。

注意:为了好演示,这里给的每页大小是5,真实的场景并非如此。

查询第二页的数据sql:

select * from brand where name like '%苏三%' 
order by edit_date desc limit 5,5;

执行结果:084dba9091f565f8c9ba05f51f887874.png从图中看到,在第二行,出现了正好等于苏三这两个字的数据。

用户搜索关键字:苏三 时,前端页面在调用品牌查询接口,pageNo默认是1。由于能够匹配关键字的数据太多了,第一页返回不完,需要多页才能全部返回。

前端获取到第一页的数据后,跟关键字:苏三 做比较,发现没有等于苏三的品牌。

这样就会在下拉控件中,自动添加一个品牌:苏三,同时在右边增加自定义标签

这样就出问题了,明明苏三这个品牌是有的,但用户还能自定义一个苏三,而不是直接选择。

2.思考123

苏三这个关键字,通过模糊查询可以查询出来,但由于品牌接口做了分页,全匹配的品牌:苏三,出现在第二页了,才导致问题的产生。

如果要解决这个问题,让它出现在第一页不就OK了?

这时候,就有下面几种解决方案。

2.1 方案1

分页查询品牌接口,pageSize是5。

我们为什么不把pageSize调大一点?比如改成:200、500等。

这样通过苏三关键字,进行模糊查询的时候,结果基本都在第一页。

这样就能非常快速的解决问题。

但有个缺点就是:如果这次调大了pageSize,但后面查询关键字的品牌又出现在第二页怎么办?

不可能一直改pageSize吧?

2.2 方案2

把分页查询接口的数据,拆分成两部分:

  1. 精确查询

  2. 模糊查询

在代码中做处理的时候,先根据关键字精确查询,即sql中使用name='苏三',这种方式查询一次数据。

如果没查出数据,则再直接用like '%苏三'进行模糊查询。

如果查出了一条数据,则把它放在返回结果集合中的第一位置。接下来,使用like '%苏三'进行模糊查询的时候,再加上条件 name <> '苏三'。将查出的结果,从第二个位置往后放。

这样可以拼接出你想要的集合。

但有个缺点,就是代码耦合性太大了。

2.3 方案3

之前,品牌苏三在第二页,最根本的原因是使用了edit_time字段进行逆序的。

也就是说,修改时间越大的越排在前面,而品牌苏三的修改时间很小,所以排在第二页了。

如果想品牌苏三,排在第一页,修改一下排序规则,不就搞定了?

可以改成按:id或者name字段排序。

用id字段排序,不太合适,虽说用了雪花算法,但跟修改时间类似,先插入的数据,会越小。

select * from brand where name like '%苏三%' 
order by id desc limit 5;

用它排序的结果,跟使用修改时间排序差不了太多。0eb76ea5672b44c7f339c38ee1d71ee6.png看来,只能使用name字段排序了。

3.如何排序?

我们在sql中直接对name字段,进行升序或者降序吗?

显然不是。

使用name字段降序

select * from brand where name like '%苏三%' 
order by name desc limit 5;

执行结果:618e6770ab77799722fe2e56e3223dcc.png图中并没有看到我们想要的数据。

其实,使用name字段升序,也可能在第一页查不出我们所想要的数据。

到底该如何处理呢?

假如,我们有这样一种排序:

  1. 全匹配显示在最前面,比如:苏三。

  2. 数据左半部分匹配,右边按字母排序,比如:苏三1、苏三2、苏三说技术。

  3. 从中间开始匹配,比如:1苏三、2苏三。

  4. 第2步和第3步,还要根据字符长度排序,字符短的排在前面,比如:1苏三、1苏三1、苏三说技术。

如果我们能实现上面的这种排序方式,这个问题就能完美解决了。

说起来容易,做起来难。

难道要先全匹配:name='苏三',再有匹配:name like '苏三%',再左匹配:name like '%苏三',把查询三次的结果组装起来?

显然这种做法有点low。

要实现上面我们设想的排序方式,在es中更好处理一下,但在mysql中要怎么处理呢?

4.解决方案

其实,我们可以换一种思路,根据字符的长度排序

mysql给我们提供了很多非常有用的函数,比如:char_length

通过该函数就能获取字符长度。

sql调整如下:

select * from brand where name like '%苏三%' 
order by char_length(name) asc limit 5;

name字段使用关键字模糊查询之后,再使用char_length函数,获取name字段的字符长度,然后按长度升序

仅这一个骚操作,就搞定需求了:15f086cb1fb01cafc57594dd25413fcd.png我们所期待的:苏三,终于排在第一个了。同时由于该sql做了分页的,即使name字段在查询时丢失了索引,执行效率也不会太低。

业务上的需求搞定了。

但追求完美的我们,好奇,想看看第二页是什么情况:

select * from brand where name like '%苏三%' 
order by char_length(name) asc limit 5,5;

执行结果:e5fc1265359a3cd5d66050ca70342058.png并没有按照我们设想的剧本进行下去,我们之前假设的3条排序中,第2条和第3条都没有满足。

这时该怎么办?

答:可以使用mysql中的locate函数,通过它可以匹配的关键字,在字符串中的位置。

使用locate函数改造之后sql如下:

select * from brand where name like '%苏三%' 
order by char_length(name) asc, locate('苏三',name) asc limit 5,5;

执行结果:bc9fb6a1dc1bbf5efc718cd874aa7970.png完美,终于出现我们想要的结果了。

除此之外,还可以使用:instrposition函数,它们的功能跟locate函数类似,在这里我就不一一介绍了,感兴趣的小伙伴可以找我私聊。

5. 总结

其实,模糊查询分页,如果分开用,一般是没问题的。

但如果它们要一起使用,一定要考虑排序问题。

如果只是按照简单的时间或者id排序,有些特殊的业务场景,没办法满足,很容易出现bug。

当然解决上面问题,还有其他办法,比如:pageSize调大一点,或者把全匹配放到第一页。

但更优的方案,是通过mysql的函数来解决问题。

我们可以通过mysql提供的:char_lengthlocateinstrposition函数等,来实现很多复杂的排序功能。

最后说一句(求关注,别白嫖我)

如果这篇文章对您有所帮助,或者有所启发的话,帮忙扫描下发二维码关注一下,您的支持是我坚持写作最大的动力。

求一键三连:点赞、转发、在看。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/543970.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

导致事务@Transactional失效的5种场景!

作者 | 磊哥来源 | Java面试真题解析&#xff08;ID&#xff1a;aimianshi666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;一个程序中不可能没有事务&#xff0c;而 Spring 中&#xff0c;事务的实现方式分为两种&#xff1a;编程式事务和声…

操作系统 cpu调度_CPU调度| 操作系统

操作系统 cpu调度调度标准 (Scheduling Criteria) There are many criteria which have been suggested for comparing the CPU scheduling algorithms. The characteristics which are used for comparison and then used to determine the best algorithms, for this some of…

IOS中KVO模式的解析与应用

最近老翁在项目中多处用到了KVO&#xff0c;深感这种模式的好处。现总结如下&#xff1a; 一、概述 KVO,即&#xff1a;Key-Value Observing&#xff0c;它提供一种机制&#xff0c;当指定的对象的属性被修改后&#xff0c;则对象就会接受到通知。简单的说就是每次指定的被观察…

使用 lambda 实现超强的排序功能

我们在系统开发过程中&#xff0c;对数据排序是很常见的场景。一般来说&#xff0c;我们可以采用两种方式&#xff1a;借助存储系统&#xff08;SQL、NoSQL、NewSQL 都支持&#xff09;的排序功能&#xff0c;查询的结果即是排好序的结果查询结果为无序数据&#xff0c;在内存中…

java 的23种设计模式 之单身狗和隔壁老王的故事

2019独角兽企业重金招聘Python工程师标准>>> 觉得代码写的别扭了&#xff0c;回头翻翻java 的23种设计模式。today,额,这么晚了&#xff0c;困了。就弄个最简单的单例模式吧。单例模式&#xff1a;俗称单身狗 package singleton; public class SingleTon { private …

使用python学线性代数_二项式过程| 使用Python的线性代数

使用python学线性代数When we flip a coin, there are two possible outcomes as head or tail. Each outcome has a fixed probability of occurrence. In the case of fair coins, heads and tails each have the same probability of 1/2. In addition, there are cases in …

工作中常见的 6 种设计模式,你用过几种?

前言 哈喽&#xff0c;大家好。平时我们写代码呢&#xff0c;多数情况都是流水线式写代码&#xff0c;基本就可以实现业务逻辑了。如何在写代码中找到乐趣呢&#xff0c;我觉得&#xff0c;最好的方式就是&#xff1a;使用设计模式优化自己的业务代码。今天跟大家聊聊日常工作中…

这12款idea插件,能让你代码飞起来!

前言基本上每个程序员都会写代码&#xff0c;但写代码的速度不尽相同。为什么有些人&#xff0c;一天只能写几百行代码&#xff1f;而有些人&#xff0c;一天可以写几千行代码&#xff1f;有没有办法&#xff0c;可以提升开发效率&#xff0c;在相同的时间内&#xff0c;写出更…

node js 开发网站_使用Node JS开发网站

node js 开发网站You will have your own fully functional website running on "localhost" after going through this article. 阅读完本文后&#xff0c;您将在“ localhost”上运行自己的功能齐全的网站 。 Basic knowledge of JavaScript and HTML is a prereq…

Java:LocalDate / LocalDateTime加减时间

在线API参考&#xff1a;LocalTime (Java Platform SE 8 ) 方法介绍 方法1方法1说明plusYears(long years) minusYears(long years) 返回增加/减少了年数的副本plusMonths(long months) minusMonths(long months)返回增加/减少了月数的副本plusWeeks(long weeks) minusWeeks(…

集合 List 分片的 5 种实现

作者 | 磊哥来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;前些天在实现 MyBatis 批量插入时遇到了一个问题&#xff0c;当批量插入的数据量比较大时&#xff0c;会导致程序执行报错&a…

使用它给 ​xxl-job 添加任务,太爽了

xxl-job是一款非常优秀的任务调度中间件&#xff0c;轻量级、使用简单、支持分布式等优点&#xff0c;让它广泛应用在我们的项目中&#xff0c;解决了不少定时任务的调度问题。我们都知道&#xff0c;在使用过程中需要先到xxl-job的任务调度中心页面上&#xff0c;配置执行器ex…

dubboSPI机制浅谈

2019独角兽企业重金招聘Python工程师标准>>> &#xfeff;&#xfeff;&#xfeff;本文重点讲述SPI机制&#xff0c;从jdk和dubbo 1、jdk spi机制 2、dubbo spi实现 首先spi是什么&#xff1f; SPI是为某个接口寻找服务实现的机制。为了实现在模块装配的时候能不在…

彻底搞懂 SpringBoot 中的 starter 机制

前言我们都知道&#xff0c;Spring的功能非常强大&#xff0c;但也有些弊端。比如&#xff1a;我们需要手动去配置大量的参数&#xff0c;没有默认值&#xff0c;需要我们管理大量的jar包和它们的依赖。为了提升Spring项目的开发效率&#xff0c;简化一些配置&#xff0c;Sprin…

Java 中验证时间格式的 4 种方法

大家好&#xff0c;今天咱们来讲一下&#xff0c;Java 中如何检查一个字符串是否是合法的日期格式&#xff1f;为什么要检查时间格式&#xff1f;后端接口在接收数据的时候&#xff0c;都需要进行检查。检查全部通过后&#xff0c;才能够执行业务逻辑。对于时间格式&#xff0c…

Redis 实现分布式锁的 7 种方案

前言日常开发中&#xff0c;秒杀下单、抢红包等等业务场景&#xff0c;都需要用到分布式锁。而Redis非常适合作为分布式锁使用。本文将分七个方案展开&#xff0c;跟大家探讨Redis分布式锁的正确使用方式。如果有不正确的地方&#xff0c;欢迎大家指出哈&#xff0c;一起学习一…

css复选框样式_使用CSS样式复选框

css复选框样式Introduction: 介绍&#xff1a; Sometimes we want to develop a website or web page that would contain a form and through that form, we want to get some information from the user. Now that information could be of any type depending on the kind …

javascript对话框_JavaScript中的对话框

javascript对话框JavaScript对话框 (JavaScript Dialog Boxes) Dialog boxes are a great way to provide feedback to the user when they submit a form. In JavaScript, there are three kinds of Dialog boxes, 对话框是向用户提交表单时提供反馈的好方法。 在JavaScript中…

排查死锁的 4 种工具,秀~

作者 | 磊哥来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;死锁&#xff08;Dead Lock&#xff09;指的是两个或两个以上的运算单元&#xff08;进程、线程或协程&#xff09;&#xf…