zoukankan      html  css  js  c++  java
  • MyBatis中模糊搜索使用like匹配带%字符时失效问题

    1.问题背景

    Mybatis是我们日常项目中经常使用的框架,在项目中我们一般会使用like查询作为模糊匹配字符进行搜索匹配,下面的Mapper.xml是我们使用like在项目中进行模糊匹配的常用方式:

    <sql id="searchCondition">
        <trim prefix="where" prefixOverrides="and|or">  
            <if test="paramVo.detail != null and paramVo.detail != '' ">
              and idwl.detail like concat('%', #{paramVo.detail, jdbcType=VARCHAR}, '%')
            </if>
         </trim>  
    </sql>

    这样使用模糊查询在分页搜索中可以解决90%的匹配搜索功能,但是,还是有10%是阴沟翻船的事情。比如现在我要匹配文件名detail中带有'%'的文件,使用这个语句就会造成搜索失效,直接返回表中的limit所有数据。

    造成这样结果的原因就是由于像'%'或者'_'这样的字符是通配字符,在模糊匹配的时候需要进行转义执行,mysql执行解析器才会把它当成是单个字符进行匹配,否则则会按照匹配两个''字符进行模糊匹配,得出全表搜索的错误结果。

    2.解决方法

    2.1.在入参SearchVo上进行特殊符号relpace转换

    使用Vo入参接收类对前端传入的detail字段进行判别处理,优先替换replace特殊字符:

    public class SerachParamVO {
        private String productVersion;
        private String detail;
        private Integer releaseType;
        private String createUser;
        private String createUserAccount;
        private Date createTime;
        private String description;
    
        public void setDetail(String detail) {
            this.detail = detail.replaceAll("%", "\\%")
                    .replaceAll("_", "\\_");
        }
    }

    2.2.使用ESCAPE

    使用ESCAPE:escape简单来说就是escape '字符'表示在like中从带有'字符'之后不再作为通配字符具有特殊含义,escape的理解可以参考另外一篇博客:

    MYSQL escape用法 ,这里就不再做详细介绍。

     对应的解决方式如下:

    ①修改sql查询语句,添加escape:

    <sql id="searchCondition">
        <trim prefix="where" prefixOverrides="and|or">  
            <if test="paramVo.detail != null and paramVo.detail != '' ">
              and idwl.detail like concat('%', #{paramVo.detail, jdbcType=VARCHAR}, '%') escape '/'
            </if>
         </trim>  
    </sql>

    ②传入SearchVo进行通配符设置:

    public class SerachParamVO {
        private String productVersion;
        private String detail;
        private Integer releaseType;
        private String createUser;
        private String createUserAccount;
        private Date createTime;
        private String description;
    
        public void setDetail(String detail) {
            this.detail = detail.replaceAll("%", "/%")
                    .replaceAll("_", "/_");
        }
    }

    2.3.总结

    以上两种方式本质都是对查询的关键字进行了处理,第一种方式更直接简洁,第二种方式更容易理解。两种方式我个人更推荐第一种。

    另外还有一种处理方式是在代码中使用拦截器或者AOP等技术进行统一拦截处理,有兴趣的小伙伴可以搜索了解一下。涉及代码较多,这里就不再一一展开。

    本博文写作要感谢“阿飞云”提供博文参考:

    Mybatis中Like的使用方式以及一些注意点

    写的非常不错,也在工作中解决了我的一个Bug单问题,可以结合一起作为参考。

  • 相关阅读:
    MFC新建菜单项
    java连接mysql
    装visio 2007遇到了1706错误,解决办法
    Oracle协议适配器错误解决办法
    powershell 开启开发人员仪表盘
    sharepoint stsadm 创建网站脚本
    网站安全修复笔记1
    sharepoint ribbon添加菜单
    解决 由于代码已经过优化或者本机框架位于调用堆栈之上,无法计算表达式的值
    RDA实现SQL CE与SQL Server间数据存取
  • 原文地址:https://www.cnblogs.com/yif0118/p/15345931.html
Copyright © 2011-2022 走看看