mybatis 转义(手把手讲解)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观
前言
在数据库操作中,MyBatis 是 Java 开发者广泛使用的 ORM 框架。然而,许多开发者在使用 MyBatis 时,会遇到 SQL 语句中的特殊字符处理问题,例如单引号、百分号(%)或反斜杠(\)等。这些问题往往会导致 SQL 语法错误或安全漏洞。本文将围绕 mybatis 转义这一核心主题,通过循序渐进的方式,结合实际案例和代码示例,帮助读者理解转义的原理、常见场景及解决方案。
MyBatis 转义的核心概念
什么是转义?
转义(Escape)在计算机领域指通过特定符号或方法,将原本具有特殊含义的字符“翻译”为普通字符的过程。例如,在 SQL 语句中,单引号(')用于表示字符串的开始和结束,若直接在字符串中插入单引号,会导致语法错误。此时需要通过转义符号(如反斜杠 \)将其转换为普通字符。
比喻:可以将转义想象成“翻译官”,当遇到需要特殊处理的字符时,它会将其转换为数据库能理解的“安全形态”,从而避免语法错误或逻辑漏洞。
MyBatis 转义的两种方式
MyBatis 提供了两种转义方式:
-
预编译参数(#{})
这是 MyBatis 推荐的写法,通过预编译参数将用户输入的值与 SQL 语句分离,框架会自动处理特殊字符的转义。例如:<select id="selectUserByName" resultType="User"> SELECT * FROM users WHERE name = #{name} </select>
当
name
参数值为'O'Reilly'
时,MyBatis 会自动将其转换为'O''Reilly'
,确保 SQL 语句的完整性。 -
字符串拼接(${})
此方式直接将参数值拼接到 SQL 语句中,不会进行自动转义。因此,若参数值包含特殊字符,需手动处理。例如:<select id="selectUserByName" resultType="User"> SELECT * FROM users WHERE name = '${name}' </select>
若
name
参数值为'O'Reilly'
,则拼接后的 SQL 语句会是:SELECT * FROM users WHERE name = 'O'Reilly'
这将导致语法错误,因为单引号未被转义。
常见场景与解决方案
场景 1:字符串中的单引号
问题:用户输入包含单引号的姓名,如 'O'Reilly'
。
解决方案:使用 #{}预编译参数
,MyBatis 会自动转义单引号。
示例代码:
public interface UserMapper {
@Select("SELECT * FROM users WHERE name = #{name}")
User findByName(@Param("name") String name);
}
当调用 findByName("O'Reilly")
时,生成的 SQL 语句为:
SELECT * FROM users WHERE name = 'O''Reilly'
场景 2:通配符(% 或 _)的转义
在 LIKE 子句中,%
和 _
是通配符。若用户输入中需要匹配这些字符本身,则需进行转义。
示例:
用户搜索包含 %
的字符串,如 "100% 完成"
。
<select id="searchText" resultType="String">
SELECT text FROM articles WHERE content LIKE CONCAT('%', #{keyword, jdbcType=VARCHAR}, '%')
</select>
此时,若 keyword
为 100%
,MyBatis 会自动将 %
转义为 %%
,生成:
SELECT text FROM articles WHERE content LIKE '%100%%%'
场景 3:特殊符号的直接拼接
在动态 SQL 或复杂查询中,若必须使用 ${}
拼接字符串,需手动转义特殊字符。
案例:动态生成排序字段和方向:
<select id="queryWithSort" resultType="User">
SELECT * FROM users
ORDER BY ${sortField} ${sortDirection}
</select>
若 sortField
为 "name DESC"
,则需手动转义空格和关键字:
Map<String, String> params = new HashMap<>();
params.put("sortField", "name");
params.put("sortDirection", "DESC");
进阶技巧:自定义转义规则
1. 使用 EscapeStrategy
接口
MyBatis 允许开发者自定义转义策略。例如,若需将反斜杠(\)作为转义符,可实现 EscapeStrategy
接口:
public class CustomEscapeStrategy implements EscapeStrategy {
@Override
public String escapeString(String s) {
return s.replace("\\", "\\\\").replace("'", "''");
}
}
然后在 MyBatis 配置文件中指定该策略:
<configuration>
<settings>
<setting name="escapeStringHandler" value="com.example.CustomEscapeStrategy"/>
</settings>
</configuration>
2. 动态 SQL 中的条件转义
在 <if>
标签中处理特殊字符:
<select id="searchUsers" resultType="User">
SELECT * FROM users
<where>
<if test="name != null">
AND name LIKE CONCAT('%', #{name}, '%')
</if>
<if test="email != null">
AND email = #{email}
</if>
</where>
</select>
此示例中,name
参数会自动转义,而 email
参数因使用 #{}
也无需额外处理。
实战案例:处理用户输入的复杂查询
案例背景
用户希望搜索包含特定符号(如 #
或 $
)的文本,并按自定义排序。
错误示例
<!-- 错误写法:直接拼接导致 SQL 注入风险 -->
<select id="searchWithCustomSort" resultType="Article">
SELECT * FROM articles
WHERE content LIKE '%${keyword}%'
ORDER BY ${sortField} ${sortDirection}
</select>
若 keyword
为 '%' OR 1=1--
,则 SQL 可能被篡改成:
SELECT * FROM articles WHERE content LIKE '%' OR 1=1--%'
这会导致全表数据泄露。
正确实现
<!-- 正确写法:使用预编译参数并限制排序字段 -->
<select id="searchWithCustomSort" resultType="Article">
SELECT * FROM articles
WHERE content LIKE CONCAT('%', #{keyword}, '%')
ORDER BY
<choose>
<when test="sortField == 'title'">title</when>
<when test="sortField == 'date'">date</when>
<otherwise>id</otherwise>
</choose>
${sortDirection}
</select>
通过枚举限制 sortField
的合法值,并结合 #{}
转义 keyword
,确保安全性。
总结与最佳实践
关键知识点回顾
- 预编译参数(#{})是 MyBatis 转义的首选方式,能自动处理特殊字符并防止 SQL 注入。
- 字符串拼接(${})需谨慎使用,必须手动转义或限制输入内容。
- 动态 SQL 中的条件逻辑需结合
<if>
和<choose>
标签,避免直接拼接用户输入。 - 自定义转义策略可通过
EscapeStrategy
接口扩展,满足复杂场景需求。
最佳实践建议
- 始终优先使用
#{}
:除非绝对必要(如动态表名),否则避免使用${}
。 - 对用户输入进行白名单校验:例如,限制排序字段为预设值,防止非法操作。
- 结合日志和测试:通过 MyBatis 的日志功能(如
log4j
)记录生成的 SQL,验证转义效果。
通过本文的讲解,开发者应能掌握 mybatis 转义的核心方法,并在实际项目中避免因字符处理不当引发的错误或安全漏洞。掌握这些技巧后,不仅能提升代码的健壮性,还能为团队协作和系统维护打下坚实的基础。