MyBatis中LIKE配合CONCAT实现安全模糊查询详解
在MyBatis开发中,使用LIKE进行模糊查询时,直接拼接百分号容易引发SQL注入风险或执行异常。通过利用数据库内置的concat函数将动态参数包裹在单引号内,可以有效解决此问题,确保查询既灵活又安全。本文将对比不同写法的优劣,并提供标准的XML配置示例。
传统写法与潜在风险
许多初学者在编写MyBatis XML映射文件时,习惯直接在全称前后添加百分号:
<select id="findUserByLikeName" parameterType="java.lang.String" resultMap="user">
select * from t_user where name like '%#{name}'
</select>
这种写法存在两个主要问题:一是部分数据库驱动或版本不支持直接在占位符周围使用字符串字面量拼接,可能导致解析错误;二是如果参数中包含特殊字符而未做转义处理,可能增加SQL注入的风险或导致逻辑错误。此外,这种写法可读性较差,且不符合预处理语句的最佳实践。
推荐方案:使用 CONCAT 函数
为了安全、规范地实现模糊查询,推荐使用数据库提供的 CONCAT 函数。该方法的核心思想是将动态参数作为函数的一个输入项,而左右两侧的百分号则作为固定的字符串参数传入数据库引擎进行处理。由于 #{} 会被视为预编译参数,数据库会在运行时将其安全地填入,从而避免了注入攻击。
第1步:配置 MySQL 环境下的 SELECT 语句
在 MySQL 数据库中,CONCAT 函数非常常用。以下是一个完整的 Mapper XML 片段,展示了如何在条件查询中安全地使用 like concat() 组合。
<!-- CONCAT 写法可防止 SQL 注入,适用于 MySQL -->
<select id="findUserByLikeName3" parameterType="java.lang.String" resultMap="user">
select * from t_user
where name like concat('%', #{name,jdbcType=VARCHAR}, '%')
</select>
操作要点:
- 入口参数:
#{name}使用#{}而非${},确保是预编译参数。 - 数据类型:明确指定
jdbcType=VARCHAR,增强类型安全性。 - 函数结构:将百分号
'%'放在单引号中,作为CONCAT的参数,中间插入动态变量。
第2步:在实际业务场景中的应用(如登录日志查询)
在实际项目中,模糊查询通常伴随其他筛选条件。以下是 RuoYi 框架中常见的登录日志查询示例,展示了如何在复杂查询中混合使用等值匹配和模糊搜索。
<select id="selectLogininforList" parameterType="SysLogininfor" resultMap="SysLogininforResult">
select info_id, login_name, ipaddr, login_location, browser, os, status, msg, login_time
from sys_logininfor
<where>
<if test="ipaddr != null and ipaddr != ''">
AND ipaddr like concat('%', #{ipaddr}, '%')
</if>
<if test="status != null and status != ''">
AND status = #{status}
</if>
<if test="loginName != null and loginName != ''">
AND login_name like concat('%', #{loginName}, '%')
</if>
<if test="params.beginTime != null and params.beginTime != ''">
<!-- 开始时间检索 -->
and date_format(login_time,'%y%m%d') >= date_format(#{params.beginTime},'%y%m%d')
</if>
<if test="params.endTime != null and params.endTime != ''">
<!-- 结束时间检索 -->
and date_format(login_time,'%y%m%d') <= date_format(#{params.endTime},'%y%m%d')
</if>
</where>
</select>
关键细节说明:
- 动态 SQL 标签:使用
<if>标签判断参数是否为空,避免生成错误的 SQL 语法。 - 多字段模糊搜索:无论是 IP 地址还是登录名,均统一采用
concat('%', #{param}, '%')的结构,保持代码风格一致且安全。 - 时间范围处理:结合
date_format函数实现日期范围的精确比较,注意符号>和<的转义书写。
注意事项与排错指南
在使用 concat 进行模糊查询时,需注意不同数据库的差异:
- 数据库兼容性:虽然 MySQL、Oracle、PostgreSQL 均支持
CONCAT,但语法细节可能略有不同(例如 Oracle 中也可以使用 || 运算符,但 MyBatis 层面建议统一使用函数以增强可读性)。 - 性能影响:模糊查询中的左通配符(如
%value)会导致索引失效。如果数据量较大,建议考虑使用全文索引(Full-Text Index)或引入 Elasticsearch 等搜索引擎替代传统的 LIKE 查询。 - 参数为空处理:确保后端 Java 代码中对 null 和空字符串做了有效过滤,或在 MyBatis 中使用
<if test="...">避免传递无效参数。
总结
在 MyBatis 开发中,摒弃直接的字符串拼接写法,转而使用数据库内置的 CONCAT 函数包裹 #{} 参数,是实现安全、健壮模糊查询的标准做法。这不仅能够防止 SQL 注入,还能提高代码的可读性和可维护性。希望上述示例能为你的项目开发提供参考。
以上就是 MyBatis 中 LIKE 配合 CONCAT 实现安全模糊查询的详细内容,更多关于 MyBatis 高级用法与 SQL 安全的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













