MyBatis LanguageDriver 增强插件 · 30 秒上手 · 语法速览 · 工作原理 · 详细语法 · 常见问题
1. 加依赖
<dependency>
<groupId>io.github.luo-zhan</groupId>
<artifactId>simple-mybatis</artifactId>
<version>0.1.0</version>
</dependency>首个版本正在发布中,若中央仓库暂未同步完成,可先
git clone后mvn install本地安装。
2. 一行配置全局启用(存量 SQL 完全兼容,不改一行也能运行)
Spring Boot(mybatis-spring-boot-starter):
# application.properties
mybatis.default-scripting-language-driver=io.github.luozhan.simplemybatis.EnhancedLanguageDriver纯 MyBatis(无 Spring):
<!-- mybatis-config.xml -->
<settings>
<setting name="defaultScriptingLanguage"
value="io.github.luozhan.simplemybatis.EnhancedLanguageDriver"/>
</settings>Spring Boot 的这个属性需 mybatis-spring 2.0.2+;更老的版本用
ConfigurationCustomizer配置,写法见 faq.md 第 1 节。
3. 开始写
<select id="findUsers" resultType="User"><![CDATA[
select * from t_user
# where id = :id
# and name like %:name%
# and status in (:statusList)
order by id
]]></select>- 参数为空的行自动省略该行条件;
- 集合、字符串、null 一起判空;
#在 sql 里天然就是注释——粘贴到db工具直接可运行
| 痛点 | 原生 MyBatis | simple-mybatis |
|---|---|---|
| 动态条件 | <if test="..."> 3行 |
# and col = :col,一行 |
| LIKE 模糊 | <bind> + <if> 4行 |
like %:name%一行 |
| IN 集合 | <foreach> 5行 |
in (:list) 一行 |
| UPDATE SET | <set> + <if> |
#set col = :val,...一行 |
| 自定义条件 | <if test="a > 0">...</if> |
#(a > 0) ... 更简便 |
| XML 转义 | < > & 逐个转义 |
CDATA 无脑全包裹即可 |
| DB 工具调试 | 挨个删标签、改参数 | 直接拷贝,# 行自动变注释 |
每一段增强语法都能被启动期翻译成等价的原生 MyBatis 结构,不用担心性能影响
# 标记到行尾为止,参数为空则自动隐藏
|
simple-mybatis 🚀 select * from t_user
# where id = :id
# and name = :name
# and status in (:statusList)
|
原生 MyBatis 🐢 <where>
<if test="id != null and id != ''">
and id = #{id}
</if>
<if test="name != null and name != ''">
and name = #{name}
</if>
<if test="statusList != null
and statusList.size() > 0">
and status in
<foreach collection="statusList" item="i"
open="(" separator="," close=")">
#{i}
</foreach>
</if>
</where> |
:name 等价于 #{name},更简洁(不推荐使用mybatis的${name},存在SQL注入风险)。
支持 %:x% / :x% / %:x 三种形式,启动期自动展开为 <bind> + like #{...},跨数据库安全。
# and name like %:name% → <bind> + like #{...}
# and code like :code%
# and tail like %:tail# and status in (:statusList)启动期翻译为 <foreach>,null 或空集合时整个 IN 条件被移除。
集合中任一元素匹配即命中(典型场景:路径前缀匹配任一权限),通配符三形式与 like 一致,作用于每个元素。
# and org_path like any (:pathList%)启动期翻译为 OR 连接的 <foreach>,null 或空集合时整个条件被移除。
update t_user
# set name = :name, age = :age
where id = :id展开为 <set> + <if>,只有非空字段参与更新。结尾多余的逗号自动去除(最后一个字段写不写逗号都可以),where 会终止 set 区域。
insert into t_user (name, age, status)
# values (:userList[].name, :userList[].age, :defaultStatus)展开为 <foreach> 多行 values。[] 是集合边界标记,标记之前是集合路径,之后是元素属性
默认判空覆盖 95% 场景;需要自定义时用括号包裹 OGNL 表达式,等价 <if test="...">。
select * from t_user
#(id != null && id > 0) where id = :id
#(type == 'a') and name like %:name%
#(type == 'b') and status = :status原生 MyBatis 里 <if> 一旦放进 CDATA 就变成文本,转义变得繁琐。而simple-mybatis可以把整段 SQL 用 CDATA 包起来,< / > / & 都不用管。
<select id="find" resultType="User"><![CDATA[
select * from t_user
where age > 10
# and type > :type
]]></select>- 只在启动期跑一次 — MyBatis 初始化 Mapper 时,
EnhancedLanguageDriver将增强语法翻译成标准<if>/<where>/<set>/<foreach>/<bind>+#{}。翻译结果作为SqlSource缓存。 - 运行期是纯原生 MyBatis — 参数绑定、SQL 组装、PreparedStatement 生成全部走
XMLLanguageDriver,与手写 XML 完全一致。没有反射热路径,没有额外 AST 解析。 - 原生语法是超集 — 你的存量 SQL 可以不改一行直接运行;也可以在同一条 SQL 内混用(不推荐)。
- 可扩展 — 通过
DirectiveSPI +ServiceLoader,可以注册自定义#xxx语法。
| 项 | 值 |
|---|---|
| Java | 8+ |
| MyBatis | 3.2.0 ~ 3.5.x(实测 3.5.x,建议 3.4.6+) |
| 第三方依赖 | 无(仅 MyBatis,provided) |
| 入口 | XML Mapper · @Select / @Update / @Insert / @Delete 注解 |
| 关闭增强 | 单条 SQL 上用 lang / @Lang 强制走原生解析 |
极少数场景想跳过增强解析(例如 PostgreSQL 特有语法 col::int 与 #(expr) 冲突),用 MyBatis 官方能力即可:
<select id="rawSql" lang="org.apache.ibatis.scripting.xmltags.XMLLanguageDriver">
select * from t_user where col::int = #{value}
</select>@Lang(XMLLanguageDriver.class)
@Select("select * from t_user where col::int = #{value}")
User rawSql(@Param("value") Integer value);- 完整语法手册:syntax-guide.md — 所有语法糖、最佳实践、注解 vs XML、边界行为
- 常见问题与边界规则:faq.md — 配置没生效、如何自查翻译结果、异常含义、不报错却出错的陷阱
- 反馈 / 建议:欢迎在 GitHub Issues 提出