MyBatis中LIKE配合CONCAT实现安全模糊查询详解

小石头
小石头
发布时间:2026-10-16| 6人浏览过
原创

在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') &gt;= date_format(#{params.beginTime},'%y%m%d')
        </if>
        <if test="params.endTime != null and params.endTime != ''">
            <!-- 结束时间检索 -->
            and date_format(login_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
        </if>
    </where>
</select>

关键细节说明:

  • 动态 SQL 标签:使用 <if> 标签判断参数是否为空,避免生成错误的 SQL 语法。
  • 多字段模糊搜索:无论是 IP 地址还是登录名,均统一采用 concat('%', #{param}, '%') 的结构,保持代码风格一致且安全。
  • 时间范围处理:结合 date_format 函数实现日期范围的精确比较,注意符号 &gt; 和 &lt; 的转义书写。

注意事项与排错指南

在使用 concat 进行模糊查询时,需注意不同数据库的差异:

  1. 数据库兼容性:虽然 MySQL、Oracle、PostgreSQL 均支持 CONCAT,但语法细节可能略有不同(例如 Oracle 中也可以使用 || 运算符,但 MyBatis 层面建议统一使用函数以增强可读性)。
  2. 性能影响:模糊查询中的左通配符(如 %value)会导致索引失效。如果数据量较大,建议考虑使用全文索引(Full-Text Index)或引入 Elasticsearch 等搜索引擎替代传统的 LIKE 查询。
  3. 参数为空处理:确保后端 Java 代码中对 null 和空字符串做了有效过滤,或在 MyBatis 中使用 <if test="..."> 避免传递无效参数。

总结

在 MyBatis 开发中,摒弃直接的字符串拼接写法,转而使用数据库内置的 CONCAT 函数包裹 #{} 参数,是实现安全、健壮模糊查询的标准做法。这不仅能够防止 SQL 注入,还能提高代码的可读性和可维护性。希望上述示例能为你的项目开发提供参考。

以上就是 MyBatis 中 LIKE 配合 CONCAT 实现安全模糊查询的详细内容,更多关于 MyBatis 高级用法与 SQL 安全的资料请关注本站其它相关文章!

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。