你在 MyBatis 里学的东西,真的都是“收益”吗?

MyBatis 官网、文档、社区都在告诉你:它帮你解决了 SQL 和 Java 的分离问题、动态 SQL 问题、结果映射问题。它有一整套体系:Mapper 接口、XML 配置、OGNL 表达式、几十个标签、上百个属性、十几个注解……

你学会这些东西,就能在 XML 里拼字符串了。

但这些问题,Spring JDBC 解决不了吗?

答案是:Spring JDBC 本来就能做,而且不需要你额外学任何东西。

下面这张表,列出了你为了在 XML 里拼一个字符串,需要学习的所有“收益”。


一、为了“挂接”SQL,你学到的收益

MyBatis 概念 它的作用 这个“收益”是真实的吗?
Mapper 接口 定义方法,XML 里的 id 要跟方法名一致 Spring JDBC 里你直接写方法,不需要这个接口。
XML 文件 存放 SQL 的地方 Spring JDBC 里 SQL 就在 Java 里,不需要另一个文件。
Namespace 区分不同 XML 文件里的同名 id Spring JDBC 没有这个问题,方法名天然唯一。
XML 文件头 <!DOCTYPE...> 那一大坨 没有 XML,就不需要这个头。
接口 ID ↔ XML id 映射 手工维护两个文件的一致性 Spring JDBC 里方法名就是方法名。
#{} vs ${} 一个参数化查询,一个直接拼接 Spring JDBC 里只有 ?,全参数化。
@Param 注解 给方法参数起别名,供 XML 引用 Spring JDBC 里参数名就是参数名。
@Mapper / @MapperScan 让 Spring 识别这个接口 Spring JDBC 里直接注入 JdbcTemplate

这一组的真实收益:把本来在一个文件里能写完的东西,拆成两个文件,然后你必须同时维护它们的一致性。


二、为了“动态拼接 SQL”,你学到的收益

MyBatis 概念 它的作用 这个“收益”是真实的吗?
<if> 标签 条件判断 Java 里 if 就能做,不需要学 XML 标签。
<where> 标签 自动处理第一个 AND 这个逻辑你自己写,三行代码。
<set> 标签 自动处理 UPDATE 末尾的逗号 这个逻辑你自己写,三行代码。
<foreach> 标签 遍历集合拼 IN 条件 Java 里 for 循环就能做。
<choose> / <when> / <otherwise> 多路分支 Java 里 if-else 就能做。
<trim> 标签 去掉前缀/后缀 Java 里 replaceAllsubstring 就能做。
<bind> 标签 在 XML 里定义变量 Java 里直接定义变量就行了。
OGNL 表达式 testitemindexcollection 你学 Java 已经学了表达式,现在还要再学一个 OGNL 的变种。

这一组的真实收益:把 Java 里的 ifforelse 替换成 XML 里的标签,换了个地方写同样的逻辑。


三、为了“控制 SQL 执行细节”,你学到的收益

MyBatis 概念 它的作用 这个“收益”是真实的吗?
fetchSize 控制 JDBC 每次取多少行 Spring JDBC 里也有,直接设置。
timeout SQL 执行超时时间 Spring JDBC 里也有,直接设置。
flushCache 清空二级缓存 Spring JDBC 没有二级缓存,不需要。
useCache 是否使用二级缓存 Spring JDBC 没有二级缓存,不需要。
statementType STATEMENT / PREPARED / CALLABLE Spring JDBC 的方法名已经区分了。
resultSetType FORWARD_ONLY / SCROLL_INSENSITIVE / SCROLL_SENSITIVE Spring JDBC 里也有对应的设置。

这一组的真实收益:把本可以直接调用的 JDBC 参数配置,塞进 XML 的属性里。


四、为了“映射结果”,你学到的收益

MyBatis 概念 它的作用 这个“收益”是真实的吗?
resultType 自动映射到普通 Java 类 Spring JDBC 里 RowMapper 一行代码。
resultMap 手动配置字段映射 Spring JDBC 里 RowMapper 直接按字段名匹配。
<id> 标签(在 resultMap 中) 标记主键字段 Spring JDBC 不需要区分主键。
<association> 一对一关联映射 Spring JDBC 里自己处理结果集组装。
<collection> 一对多关联映射 Spring JDBC 里自己处理结果集组装。
@Results / @Result 在接口方法上配置映射 Spring JDBC 不需要。
@One 一对一关联 本质上是再发一次查询,N+1 的源头之一。
@Many 一对多关联 本质上是再发一次查询,N+1 的源头之一。
@MapKey 指定 Map 结果的 key 字段 Spring JDBC 里自己组装 Map。
@Options 配置 useGeneratedKeysfetchSize 跟 XML 属性完全重叠,换了个地方写。
@ResultType 指定返回类型 方法签名已经决定了返回类型。

这一组的真实收益:把本来可以在 RowMapper 里直接处理的逻辑,拆成了 XML 配置或注解配置。


五、为了“配置 MyBatis 本身”,你学到的收益

MyBatis 概念 它的作用 这个“收益”是真实的吗?
mybatis-config.xml 主配置文件 Spring JDBC 没有单独的配置文件。
settings 几十个配置项 Spring JDBC 没有这些配置项。
typeAliases 包扫描,省略 XML 里的全限定类名 Spring JDBC 直接用类名,不需要别名。
plugins 拦截器配置 Spring JDBC 用 AOP,不需要学拦截器。
environments 环境配置 Spring Boot 的 application.yml 已经做了。
DatabaseIdProvider 多数据库方言切换 Spring JDBC 直接写 SQL,不需要单独配置。
<databaseId> 为不同数据库写不同版本的 SQL Spring JDBC 里你用一个变量判断就行了。

这一组的真实收益:多了一份配置文件,多了一堆配置项,多了一整套扩展机制的学习成本。


六、为了“定位错误”,你学到的收益

MyBatis 概念 它的作用 这个“收益”是真实的吗?
BindingException 参数绑定出问题了 Spring JDBC 里没有这种异常,参数直接绑定。
ExecutorException 执行器出问题了 Spring JDBC 里没有这种异常。
TooManyResultsException 预期一条但查出了多条 Spring JDBC 里 queryForObject 会抛 IncorrectResultSizeDataAccessException,但异常信息更清晰。
ReflectionException 反射出问题了 Spring JDBC 里不会因为反射失败而抛出这种异常。
CacheException 缓存出问题了 Spring JDBC 没有缓存。
PersistenceException 持久层通用异常 Spring JDBC 直接抛 DataAccessException
总计 31 类异常(MyBatis 官方源码统计) 你需要学习每一种异常的出处和含义 Spring JDBC 只有 3 类 核心异常。

这一组的真实收益:你花时间调试的不是“数据库出了什么问题”,而是“框架的哪一层又炸了”。


你学完这些“收益”,最终实现的是什么?

就是在 XML 里拼一个字符串。

  • Mapper 接口 + XML 文件 + namespace + XML 头 + 接口 ID 映射 + @Param → 为了把 SQL 放进 XML
  • 几十个标签 + OGNL 表达式 → 为了在 XML 里做动态条件判断
  • 上百个属性 → 为了控制 XML 里 SQL 的执行细节
  • 十几个注解 → 为了在接口上标注 XML 对应的配置
  • 几十个异常类 → 为了定位 XML 拼字符串时出的错
  • mybatis-config.xml + settings + plugins + typeAliases → 为了配好环境让 XML 能正常运行

所有这些概念,解决的是同一个问题:在 XML 里拼一个字符串。但你在 Java 里本来就能拼。


你用 Spring JDBC,需要的只是一个工具类

如果你把条件拼接、参数管理、分页逻辑封装成几个方法:

  • addWhere():拼接条件 + 自动收集参数
  • addIf():条件判断 + 自动决定是否拼接
  • page():分页 + 自动处理 COUNT 和 LIMIT

全工程复用,覆盖 90% 以上的业务场景。

你不再需要:

  • Mapper 接口 → 方法就在类里,不需要额外接口
  • XML 文件 → SQL 就是字符串
  • namespace → 类名和方法名天然唯一
  • XML 头 → 没有 XML 就没有头
  • #{} vs ${} → 只有 ?
  • resultType / resultMapRowMapper 直接处理
  • 几十个标签 → Java 的 if 已经够用
  • 上百个属性 → 方法参数直接设置
  • 十几个注解 → 什么都不需要
  • 几十个异常 → 数据库错误就是 SQLException
  • 拦截器 → Spring AOP 就能扩展

三个方法,解决 90% 的问题。剩下的 10%,本来就要手写 SQL,不关工具的事。


这个工具类已经有了现成的

它叫 SimpleDAO

它在 Spring JDBC 的基础上,做了这些事情:

你原本需要手写的事 SimpleDAO 做了什么
条件拼接 + 参数管理 add()and()in()notIn() 一行搞定,参数自动收集,空值自动跳过
多条件组合 + 跨位置参数合并 mergeParams(c1, c2, c3) 自动合并多个条件类的参数,顺序与 SQL 中 ? 一致,无需手动维护 Object[]
模糊查询转义 add("AND u.name LIKE ?", name, 3),site 控制 % 位置(左/右/前后),自动转义 %_,防 SQL 注入
IN 条件 in("id", ids),数组自动展开成 (?,?,?),参数自动收集
无参数 SQL 片段 + 动态开关 add("AND dr = 0")add("AND status = 1", flag),带布尔参数控制是否拼接
单表 CRUD 继承 BaseDao<T>,空类即得 saveupdatedeletefindByIdlistpagecountexists 等 20+ 方法,零代码、零 SQL
差异更新 update(T) 不更新 null 字段,updateNull(T) 更新 null 字段,按需选择
批量操作 saveBatch(list)replaceBatch(list),底层复用数据库驱动批处理能力
自动分页 page(cond) 一行搞定,自动生成 COUNT SQL,自动计算 LIMIT/OFFSET,返回 Page<T> 含数据列表 + 总条数 + 总页数;极端复杂 SQL 用 page0() 兜底(子查询法)
主键自动生成 @Id("snow") 雪花算法、@Id("uuid") UUID、@Id("auto") 数据库自增、@Id("custom") 自定义,插入时自动赋值
审计字段自动填充 save() 自动填充 createTime / createBy / drupdate() 自动填充 updateTime / updateBy
逻辑删除 delete() 自动判断表是否有 dr 字段,有则 UPDATE SET dr=1,无则 DELETE FROM
结果集映射 查询结果自动映射到实体/VO,驼峰 ↔ 下划线自动转换,无需 XML 配置
联表查询 SQL 完整手写,支持 JOIN、子查询、UNION、CTE、窗口函数、聚合统计——数据库能写啥,它就能跑啥,SQL 直接复制到客户端可执行
复杂报表 原生 SQL + BaseCondition 条件拼接,mergeParams 多条件合并,报表开发效率提升 50% 以上
数据权限 Spring AOP 切面 + cond.setExtendCondition(and) 一行注入权限条件,无侵入、零框架依赖
字段脱敏 Spring AOP 切面在 Service 层处理,不污染持久层
SQL 日志调试 自动打印带参数的完整 SQL,字符串/日期自动加引号,复制即可在数据库客户端执行,无需手动替换占位符
异常处理 数据库原生异常直接透传,不封装、不转换、不自造 31 类框架异常
原生能力保留 危机时刻可直接调用 JdbcTemplateNamedParameterJdbcTemplate,框架不挡路
框架存在感 < 5%,业务代码浓度 > 95%,没有 XML、没有 OGNL、没有 Mapper 接口、没有 SqlSession

SimpleDAO 没有替换 Spring JDBC,它只是把你本来要手写的样板代码自动化了。


开源地址

  1. 核心框架:https://gitee.com/gao_zhenzhong/simple-dao
  2. 系统底座:https://gitee.com/gao_zhenzhong/simple-dao-starter
  3. 代码生成器:https://gitee.com/gao_zhenzhong/simple-dao-coder
  4. 实战案例:https://gitee.com/gao_zhenzhong/simple-dao-demo

写在最后

MyBatis 的“收益”,加引号是认真的。因为你学了一大堆东西,得到的只是在 XML 里拼一个字符串。

SimpleDAO 的收益,不加引号也是认真的。因为它什么都没让你多学,只是帮你省掉了重复代码。

去 Gitee 拉一个 Demo,跑起来,看看代码量差多少,然后自己算账。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐