Skip to content

About

简化mybatis语法,让xml中和注解中的sql写起来更方便

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

17 Commits

Folders and files

Repository files navigation

simple-mybatis:用一个 # 号写完动态 SQL,启动期翻译为原生 MyBatis 语法

MyBatis LanguageDriver 增强插件 · 30 秒上手 · 语法速览 · 工作原理 · 详细语法 · 常见问题


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>
  1. 参数为空的行自动省略该行条件;
  2. 集合、字符串、null 一起判空;
  3. # 在 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 结构,不用担心性能影响

# — 动态条件(替代 <if>/<where>)

# 标记到行尾为止,参数为空则自动隐藏

simple-mybatis 🚀

select * from t_user
# where id = :id
# and name = :name
# and status in (:statusList)
  • 参数为空自动省略整行
  • null、空串、空集合统一按空处理
  • #where 展开为 <where>,自动处理首个 and/or
  • # 建议写在行首,一行一个条件,可读性更好

原生 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>

:param — 占位符简写

:name 等价于 #{name},更简洁(不推荐使用mybatis的${name},存在SQL注入风险)。

like %:x% — 通配符自动包装

支持 %:x% / :x% / %:x 三种形式,启动期自动展开为 <bind> + like #{...},跨数据库安全。

# and name like %:name%    →  <bind> + like #{...}
# and code like :code%
# and tail like %:tail

in (:list) — 集合自动展开

# and status in (:statusList)

启动期翻译为 <foreach>,null 或空集合时整个 IN 条件被移除。

like any (:list%) — 集合 OR 模糊匹配

集合中任一元素匹配即命中(典型场景:路径前缀匹配任一权限),通配符三形式与 like 一致,作用于每个元素。

# and org_path like any (:pathList%)

启动期翻译为 OR 连接的 <foreach>,null 或空集合时整个条件被移除。

# set col = :val, — 只更新非空字段

update t_user
# set name = :name, age = :age
where id = :id

展开为 <set> + <if>,只有非空字段参与更新。结尾多余的逗号自动去除(最后一个字段写不写逗号都可以),where 会终止 set 区域。

# values (...) — 批量 insert

insert into t_user (name, age, status)
# values (:userList[].name, :userList[].age, :defaultStatus)

展开为 <foreach> 多行 values。[] 是集合边界标记,标记之前是集合路径,之后是元素属性

#(expr) ... — 自定义 OGNL 条件

默认判空覆盖 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

CDATA 全包裹 — 告别 XML 转义

原生 MyBatis 里 <if> 一旦放进 CDATA 就变成文本,转义变得繁琐。而simple-mybatis可以把整段 SQL 用 CDATA 包起来,< / > / & 都不用管。

<select id="find" resultType="User"><![CDATA[
  select * from t_user
  where age > 10
  # and type > :type
]]></select>

工作原理

启动期翻译机制:SQL 源码 → EnhancedLanguageDriver → 原生 MyBatis 语法树 → 运行期 JDBC

  • 只在启动期跑一次 — MyBatis 初始化 Mapper 时,EnhancedLanguageDriver 将增强语法翻译成标准 <if>/<where>/<set>/<foreach>/<bind> + #{}。翻译结果作为 SqlSource 缓存。
  • 运行期是纯原生 MyBatis — 参数绑定、SQL 组装、PreparedStatement 生成全部走 XMLLanguageDriver,与手写 XML 完全一致。没有反射热路径,没有额外 AST 解析。
  • 原生语法是超集 — 你的存量 SQL 可以不改一行直接运行;也可以在同一条 SQL 内混用(不推荐)。
  • 可扩展 — 通过 Directive SPI + 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 提出

License

Apache License 2.0

About

简化mybatis语法,让xml中和注解中的sql写起来更方便

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages