Mybatis中LIKE特殊字符处理的解决方案

在MySQL使用LIKE进行模糊匹配时,特殊字符需要转义。Mybatis和Mybatis-Plus未提供自动转义,可通过实现插件接口或使用切面结合注解的方式解决。方案一利用mybatis插件接口拦截,但对某些查询方式有局限性;方案二通过AOP和自定义注解,灵活性更高且无歧义问题,适用于特定接口处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在MYSQL中,使用LIKE关键字进行模糊匹配时候,特殊字符是需要转义的,如下: \ 转义成 \\ , _ 转义成 \_ , % 转义成 \%
在mybatis和mybatis-plus中,没有提供相关的方法来自动转义。其实这是符合逻辑的,转义这种事情该交给开发者自己去处理,官方框架不去入侵这种逻辑代码也是为了更好的灵活性。
在业务开发的环境中,往往会有测试提出这样的bug:“输入特殊字符进行筛选,没有过滤掉对应的数据”。像这种问题其实本质上是不应该存在的,在根源上就应该切除掉,就是说禁止输入特殊字符进行筛选。但往往测试和产品他们根本不懂技术,你也别废口舌去和他们争论了。那么我们就来看看如何处理关于LIKE特殊字符转义问题。

方案一:实现mybatis的插件接口

我们知道mybatis提供了插件接口方便开发者进行二次开发。mybatis-plus对mybatis进行了增强,在mybatis-plus中需要实现InnerInterceptor接口进行拦截。如果只是引入的mybatis,则实现Interceptor接口进行拦截。注意一下:
该方案对 like xxx%like %xxx 的查询方式会有一定的局限性。如:
用户输入 = %a 时,业务按照 like xxx% 的语义查询,是查询xxx开头的数据。正常该转义成 like \%a%
用户输入 = a% 时,业务按照 like %xxx 的语义查询,是查询xxx结尾的数据。正常该转义成 like %a\%
但程序在转换时,依然会按照 like %xxx% 的语义去转义。这是不可避免的,因为这确实是歧义的地方。 程序解析 like %a% 时,无法完全地确定哪一部分是用户输入的,所以只有按照标准的 %xxx% 来进行解析转义。
不过在一般的业务查询中,左LIKE 和 右LIKE 很少用到,可以不用考虑此情况。
下面是实现了mybatis-plus的拦截接口,代码如下:

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.sql.SQLException;
import java.util.HashSet;
import java.util.Set;

/**
 * @author shaohuailin
 * @date 2023/10/8
 */
@Slf4j
public class LikeEscapeInnerInterceptor implements InnerInterceptor {
   

    @Override
    public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
   
        escapeLike(boundSql);
    }

    /**
     * like条件中若有关键字,则进行转义
     *
     * @param boundSql
     */
    public 
<think>好的,我现在需要帮助用户解决关于MyBatis中使用LIKE语句时,百分号%在右边的情况应该用哪个方法的问题。首先,我得回忆一下用户的历史对话,看看有没有相关的信息。之前的对话中,用户询问了Java的MultipartFile获取文件大小的方法,现在转向了MyBatisLIKE查询,这说明用户可能在开发一个Web应用,涉及文件上传和数据库操作,现在遇到了数据库查询的问题。 用户的问题是关于MyBatisLIKE语句,特别是%放在右边的情况。我需要确定在MyBatis中如何正确拼接%到查询条件中。常见的做法是使用CONCAT函数或者bind标签,或者直接在Java代码中拼接好字符串传递给XML映射文件。但用户可能希望知道MyBatis推荐的方法,或者最佳实践是什么。 首先,我要确认用户的问题具体是什么。当用户说“%在右边”,可能是指查询条件以某个字符串开头,例如查询以“abc”开头的字段,对应的SQL应该是`LIKE 'abc%'`。这时候在MyBatis中如何构造这个条件呢? 接下来,我需要考虑不同的方法来实现这一点。常见的方法有: 1. 在Java代码中拼接好带有%的字符串,然后作为参数传递给MyBatis的XML映射文件。 2. 在XML中使用CONCAT函数,例如`CONCAT(#{value}, '%')`。 3. 使用MyBatis的bind标签来动态构造查询条件。 4. 直接在XML中拼接%,例如`LIKE '${value}%'`,但这种方法可能有SQL注入的风险,不推荐使用。 用户可能希望知道哪种方法最安全、最有效。需要指出使用`${}`存在安全问题,应该使用`#{}`占位符,并结合CONCAT或者bind标签来避免SQL注入。 同时,用户可能不了解bind标签的用法,或者CONCAT函数在不同数据库中的兼容性问题。例如,有些数据库可能不支持CONCAT函数有多个参数,或者语法不同,这时候可能需要使用数据库特定的函数,比如Oracle使用`||`进行字符串连接。 另外,可能需要给出示例代码,说明每种方法的具体实现,并比较它们的优缺点。例如,直接拼接在Java中的方法虽然简单,但可能不够灵活;使用CONCAT函数在XML中更清晰,但依赖数据库的函数支持;bind标签则提供了更大的灵活性,并且可以在动态SQL中处理复杂的逻辑。 还需要提醒用户注意大小写敏感的问题,LIKE查询可能受数据库的排序规则影响,是否区分大小写,以及如何通过修改查询或数据库设置来处理。 总结下来,回答的结构应该是先介绍问题对应的场景,然后列出几种不同的实现方法,详细说明每种方法的步骤、示例代码以及注意事项,最后给出推荐的方案,并解释为什么选择这种方法。同时,要确保回答符合用户之前设定的格式要求,比如使用中文、结构清晰、步骤明确,以及正确的LaTeX格式。 最后,检查是否有遗漏,比如是否提到了SQL注入的风险,是否给出了完整的示例,是否比较了不同方法的优缺点,以及是否考虑了不同数据库的兼容性问题。确保回答准确、全面,并且易于理解,帮助用户解决实际问题。</think>在MyBatis中实现**右侧模糊查询**(`LIKE 'value%'`)的常用方法及步骤如下: --- ### 方法一:使用`CONCAT`函数(推荐) **XML映射文件示例**: ```xml <select id="searchByPrefix" resultType="YourEntity"> SELECT * FROM table WHERE column LIKE CONCAT(#{prefix}, '%') </select> ``` **特点**: - 直接通过SQL函数拼接`%` - 使用预编译参数(`#{prefix}`)避免SQL注入 - 兼容性:MySQL/Oracle/SQL Server等主流数据库均支持`CONCAT` --- ### 方法二:Java代码拼接`%` **Java调用层**: ```java String searchTerm = "abc" + "%"; // 手动添加% mapper.searchByPrefix(searchTerm); ``` **XML映射文件**: ```xml <select id="searchByPrefix" resultType="YourEntity"> SELECT * FROM table WHERE column LIKE #{prefix} </select> ``` **特点**: - 业务层控制模糊逻辑 - 适用于简单场景 --- ### 方法三:`<bind>`标签(动态SQL) **XML映射文件**: ```xml <select id="searchByPrefix" resultType="YourEntity"> <bind name="pattern" value="prefix + '%'" /> SELECT * FROM table WHERE column LIKE #{pattern} </select> ``` **特点**: - 动态生成模式 - 避免SQL注入的同时保持XML逻辑集中 - 支持复杂表达式(如多个条件组合) --- ### 方法四(不推荐):直接拼接`${}` ```xml WHERE column LIKE '${prefix}%' <!-- 存在SQL注入风险 --> ``` **风险**: - 通过`${}`直接拼接原始值 - 可能遭受SQL注入攻击 - 仅适用于完全可信的内部参数 --- ### 对比总结 | 方法 | 安全性 | 可维护性 | 数据库兼容性 | 适用场景 | |------------|--------|----------|--------------|------------------------| | `CONCAT` | ✅ | ✅ | ✅ | 简单右侧模糊查询 | | Java拼接 | ✅ | ❌ | ✅ | 少量固定模式 | | `<bind>` | ✅ | ✅ | ✅ | 动态/复杂条件 | | `${}`拼接 | ❌ | ❌ | ✅ | **严禁用于生产环境** | --- ### 完整示例(方法一+方法三) **Java调用**: ```java List<YourEntity> results = mapper.searchByPrefix("abc"); ``` **XML映射**: ```xml <!-- 使用CONCAT --> <select id="searchByPrefix" resultType="YourEntity"> SELECT * FROM users WHERE username LIKE CONCAT(#{prefix}, '%') </select> <!-- 或使用bind --> <select id="searchByPrefix" resultType="YourEntity"> <bind name="pattern" value="prefix + '%'" /> SELECT * FROM users WHERE username LIKE #{pattern} </select> ``` --- ### 注意事项 1. **大小写敏感**: - 部分数据库(如MySQL默认不区分大小写,PostgreSQL区分) - 可通过`LIKE BINARY`或修改排序规则控制 2. **性能优化**: - 右侧模糊查询可使用索引(如`LIKE 'abc%'`) - 避免左侧模糊(`LIKE '%abc'`)导致全表扫描 3. **特殊字符转义**: - 若参数包含`_`或`%`,需用`ESCAPE`子句: ```xml WHERE column LIKE CONCAT(#{prefix}, '%') ESCAPE '/' ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值