它被误解了多年却是持久层唯一的事实标准一、三分天下的历史格局Spring JDBC 和 iBatisMyBatis 的前身几乎同时代诞生Hibernate 也差不多同时期崛起。二十年前持久层领域确实是三分天下的局面。但二十年后格局发生了明显变化Hibernate被 MyBatis 蚕食了大部分市场。因为 Hibernate 太重——对象映射、关系管理、缓存机制、代理生成每一步都在增加黑盒。遇到复杂查询你往往退回原生 SQL框架的存在意义被打了个折扣。MyBatis蚕食的是 Hibernate 的市场而不是 Spring JDBC 的市场。因为 iBatis/MyBatis 本质上是一个封装层——它做的事情Spring JDBC 本来就能做只是需要多写几行样板代码。真正用惯 Spring JDBC 的人没有必要跳到另一个也要写 SQL 的框架里。Spring JDBC的市场被蚕食的比例远没有舆论说的那么大。它一直是那个“被低估但从未消失”的选项。今天的实际使用比例做一个粗略估算直接显式使用 Spring JDBC约 20%使用 MyBatis 及其衍生品约 60-70%其他JPA/Hibernate、jOOQ、原生 JDBC、自研框架等约 10-20%Spring JDBC 这 20% 的使用者几乎不在社交媒体上发声。二、为什么互联网上讨论的全是 MyBatis不是因为 MyBatis 更好是因为它坑多。越多人踩坑越多人提问越多人写博客教怎么填坑。问题越多讨论越多社区看起来越“繁荣”。Spring JDBC 没坑所以没人讨论它。没有 N1 问题需要规避没有懒加载需要配置没有一级二级缓存需要理解没有拦截器需要学习。你写什么 SQL它就执行什么 SQL。你遇到问题问题就是 SQL 本身的问题。所以你没有写博客的必要。你只需要去查 SQL 语法去查执行计划去加索引。这些不需要一个 Spring JDBC 专属的社区来帮你。一个不需要填坑的框架天然没有社区热度。三、Spring JDBC 是持久层唯一的事实标准不管你的项目用的是 MyBatis、JPA、Hibernate 还是其他持久层框架只要你跑在 Spring 生态里底层一定有一层 Spring JDBC。数据源管理、事务管理、连接池、多数据源、分库分表、分布式事务——这些能力全部建立在 Spring JDBC 之上。它不是“可选组件”它是 Spring 生态中关系型数据库访问的基础设施是事实标准。MyBatis 要在 Spring 生态里用得额外加一个 MyBatis-Spring 桥接层。JPA 要在 Spring 生态里用得额外配EntityManagerFactory和JpaTransactionManager。Spring JDBC 不需要适配任何人别人需要适配它。这就是基础设施和插件的区别。四、白盒全程透明全程可控Spring JDBC 的行为是透明的。你写SELECT * FROM user WHERE id ?它就执行SELECT * FROM user WHERE id ?。框架不帮你改字段名不帮你加额外的查询条件不趁你不注意发一条额外的 SQL。它的执行链路最多三层JdbcTemplate→PreparedStatement→ 数据库。没有动态代理没有拦截器链没有黑盒翻译。白盒的最大优势不在于“你看到 SQL 长什么样”而在于“你可以零成本介入 SQL 的生命周期”。你想加数据权限、多租户过滤、动态表名、审计日志——直接在 Java 里用if和字符串拼接就能完成。StringsqlSELECT * FROM user WHERE 11;if(需要数据权限){sql AND school_id currentUser.getSchoolId();}jdbcTemplate.query(sql,...);不需要学拦截器接口不需要操作MetaObject不需要理解BoundSql的内部结构。全程白盒 你随时有介入点且介入成本就是写一行 Java 代码。五、异常你定位的是数据库错误不是框架错误Spring JDBC 的异常体系极其精简。数据库报什么错你就看到什么错。SQL 语法错误 →SQLException。字段不存在 →SQLException。主键冲突 →SQLException。不需要额外学 31 类异常的含义。对比MyBatis 源码里有几十种异常类BindingException、ExecutorException、TooManyResultsException、ReflectionException、CacheException……你花时间学的不是“数据库出了什么问题”而是“框架的哪一层又炸了”。Spring JDBC 不制造异常它只传递异常。一个不会自己制造异常的框架调试成本天然就低。六、性能没有中间层就没有损耗Spring JDBC 的JdbcTemplate是 Spring 执行 SQL 的最后一层。到了它这里参数已经绑定了SQL 已经完整了剩下的就是发给数据库。不用经过MapperProxy的代理调用不用经过SqlSession的会话管理不用经过Executor的缓存判断不用经过StatementHandler的预编译包装不用经过ResultSetHandler的结果集二次封装。多一层抽象就多一层损耗。多一层黑盒就多一层排查成本。Spring JDBC 的链路最短性能天花板最高。七、扩展成本Spring AOP vs MyBatis 拦截器Spring JDBC 的扩展用 Spring AOP 就能完成Around(execution(* com.example..*Dao.*(..)))publicObjectinjectDataAuth(ProceedingJoinPointpjp)throwsThrowable{// 拿到 SQL追加条件继续执行}不需要学框架内部的拦截器接口不需要操作框架内部对象就是 Spring 原生的 AOP 能力。对比 MyBatis 的扩展成本MyBatis 也留了口子——拦截器。但这个口子的门槛极高。你要写一个数据权限拦截器需要实现Interceptor接口在intercept()方法里拿到Invocation对象从Invocation里取出MappedStatement和BoundSql用反射或者MetaObject修改BoundSql里的 SQL还要处理分页、缓存等边缘情况光是把 SQL 取出来就要 5 行以上的反射代码。想改参数还要处理ParameterHandler。想改返回值还要处理ResultSetHandler。在没有大语言模型的时代这套东西能挡住 80% 的程序员。你写 20 行代码可能连业务的边都摸不着。这就是为什么 MyBatis 有庞大的插件市场分页插件、数据权限插件、多租户插件、脱敏插件……不是因为 MyBatis 生态好而是因为它的扩展口成本太高大部分人自己写不出来只能等社区出方案。这不是生态繁荣这是缺口清单。八、MyBatis 社区的本质受害者联盟MyBatis 的 SQL 编写是白盒的你可以在 XML 里看到完整的 SQL 文本。但 SQL 的执行是黑盒的你无法在它发往数据库之前直接介入它。你想加一个条件必须绕过框架的限制。这个矛盾催生了大量插件。分页、数据权限、脱敏、多租户……每一个都是因为框架本身没有提供直接的能力只能靠社区插件来补。所以 MyBatis 社区的繁荣本质上是“受害者联盟”的自我强化。大家聚在一起不是因为“这玩意儿真好用”而是因为“这个问题你怎么解决的那个坑你怎么填的”。越多人用就有越多人踩坑越多人踩坑就有越多人写博客教填坑越多人教填坑看起来就越“繁荣”。Spring JDBC 不需要这个繁荣。因为全程白盒全部可控不需要插件来补缺口。一个不需要补坑的框架天然没有“繁荣”的社区。但它的沉默不代表它不存在。九、哪些场景在用 Spring JDBC互联网上讨论最多的永远是 MyBatis但 Spring JDBC 在多个重要场景里一直在稳定使用企业内部自研框架很多中大型企业内部都有自研的持久层封装全部基于 Spring JDBC。连接池、数据源、分布式事务这些基础设施没有谁会重新发明一遍。银行、金融系统对黑盒零容忍。SQL 必须完全可控执行路径必须完全清晰异常必须直接透传。Spring JDBC 是这类场景最顺理成章的选择。报表场景SQL 本身就是核心资产。复杂报表的 SQL 往往是 DBA 专门优化过的直接拿过来用就行不需要被任何框架再翻译一遍。性能敏感场景执行链路最短损耗最小。少一层抽象就少一层开销。在这些场景里Spring JDBC 不是“备选方案”是“最佳选项”。十、用 Spring JDBC 的人为什么不说话有一个事实需要面对使用 Spring JDBC 的人在技术社区的声量很低。不是因为用的人少而是因为他们被长期“鄙视”。“你怎么还在用 Spring JDBC太原始了。”“这么老的 API 还在用”时间久了他们就习惯了沉默。他们不在 CSDN 写“Spring JDBC 真香”因为他们觉得这是常识不需要讨论。他们也不跟人争论 MyBatis 好还是 Spring JDBC 好因为他们知道争论没有意义——项目跑得好好的不需要证明给谁看。沉默不代表不存在。20% 的直接使用率加上所有基于 Spring JDBC 封装的自研框架实际覆盖的项目比例远超舆论所反映的数字。十一、那么Spring JDBC 的“繁琐”是什么客观承认Spring JDBC 在使用层面确实存在繁琐性。因为它是 JDBC 的本质——它不可能提供单表对象化更不可能自动简化条件拼接。JdbcTemplate本身就是极其简洁的 API但在实际业务中你仍然需要写大量的StringBuildersqlnewStringBuilder(SELECT * FROM user WHERE 11);ListObjectparamsnewArrayList();if(name!null!name.isEmpty()){sql.append( AND name ?);params.add(name);}if(age!null){sql.append( AND age ?);params.add(age);}// ... 更多条件Object[]paramArrayparams.toArray();这是样板代码。不是框架的问题是你需要但不该自己写的东西。Spring JDBC 没有做错什么它只是“干净”到了没有帮你简化这一步的程度。所以你需要的是一个工具类而不是一个新的框架。十二、三个方法覆盖 90% 的重复工作你只需要封装三个方法addCondition()拼接条件 自动收集参数addIf()条件判断 自动决定是否拼接page()分页 自动处理 COUNT 和 LIMIT全工程复用覆盖 90% 以上的业务场景。你不需要 Mapper 接口不需要 XML 文件不需要 namespace不需要几十个标签不需要上百个属性不需要十几个注解不需要 31 类异常。你只需要能写 SQL能调方法。好我把第十三节完整重写把BaseCondition代码示例嵌入进去让读者直观看到“条件层到底长什么样”。十三、SimpleDAO 就是那个工具类的增强版前面说了Spring JDBC 的繁琐在于条件拼接和参数管理。你真正需要的不是另一个框架而是一个能把样板代码收走的工具类。SimpleDAO 就是这样一个工具类。它的核心设计是把 SQL 的稳定部分SELECT、FROM、JOIN留给你手写把高动态部分WHERE、排序、分页封装成可复用的 Java 语义单元。举个例子你在 Spring JDBC 里要写一个带 5 个条件的查询需要手动拼接字符串、手动管理参数列表。在 SimpleDAO 里你只需要继承BaseCondition在addCondition()方法里一行一个条件publicclassUserCondextendsBaseCondition{privateStringname;privateIntegerageMin;privateIntegerageMax;privateObject[]ids;privateBooleanhasOrder;OverrideprotectedvoidaddCondition(){and(name LIKE,name,3);// 模糊查询and(age ,ageMin);// 大于and(age ,ageMax);// 小于in(id,ids);// IN 集合add(AND EXISTS (SELECT 1 FROM order WHERE user_id t.id),hasOrder);// 子查询 动态开关}}六个条件六行代码。没有if判空没有字符串拼接没有params.add()。条件成立就拼接不成立就跳过参数自动收集顺序自动对齐。这个UserCond可以同时服务于单表查询、联表查询、子查询、报表统计——条件层不关心你查的是几张表它只关心“这个条件要不要加”。再看它怎么跟 SQL 配合。你写一个联表查询SQL 写在常量里条件用UserCond传进去RepositorypublicclassUserDaoextendsBaseDaoUser{privatestaticfinalStringJOIN_SQL SELECT t.*, o.order_name FROM sys_user t LEFT JOIN bus_order o ON t.id o.user_id ;publicPageUserVOpageJoin(UserCondcond){returnpage(JOIN_SQL,cond,UserVO.class);}}看到区别了吗联表查询的代码量跟单表查询没有任何区别。你不需要学新的 API不需要配额外的映射不需要装插件。SQL 是你写的条件是 Java 对象分页是page()方法。这就是把样板代码收走之后的样子。你写的每一行代码都在表达业务意图没有一行是在伺候框架。SimpleDAO 在 Spring JDBC 基础上做的增强用一张表列清楚你原本需要手写的事SimpleDAO 做了什么条件拼接 参数管理add()、and()、in()一行搞定参数自动收集单表 CRUD继承BaseDao零代码零 SQL分页page()一行自动处理 COUNT 和 LIMIT联表查询完整 SQL 手写list()自动映射 VO数据权限Spring AOP 切面注入逻辑删除delete()自动处理审计字段save()、update()自动填充SimpleDAO 没有替换 Spring JDBC 的任何能力它只是把你本来要手写的样板代码自动化了。你不需要离开 Spring JDBC 的生态因为 SimpleDAO 就长在它上面。十四、知识寿命用 Spring JDBC你学的是 JDBC、SQL、事务边界、连接池管理。这些知识二十年不变。你去任何一个 Java 项目这套东西依然管用。用 MyBatis你学的是 XML 标签、OGNL 表达式、拦截器机制。换个框架这套知识就作废了。用 JPA你学的是 JPQL 语法、Criteria API、实体生命周期管理。换个语言或框架这套知识也作废了。Spring JDBC 给你的不是“框架知识”是“数据库开发的基础认知”。这笔账你自己算。开源地址核心框架https://gitee.com/gao_zhenzhong/simple-dao系统底座https://gitee.com/gao_zhenzhong/simple-dao-starter代码生成器https://gitee.com/gao_zhenzhong/simple-dao-coder实战案例https://gitee.com/gao_zhenzhong/simple-dao-demo写在最后Spring JDBC 被误解了二十年。它不是什么“原始的工具”它是持久层唯一的事实标准。MyBatis 社区的繁荣是“受害者联盟”的自我强化。Spring JDBC 不需要这种繁荣因为它是完整的、自洽的、全程透明的。一个不需要补坑的框架自然没有那种靠填坑撑起来的社区热度。SimpleDAO 只是帮 Spring JDBC 补上了样板代码那层薄薄的手套不需要你离开这个标准。你在 Spring JDBC 里写的每一行代码都是在巩固你二十年不变的知识积累。这笔账自己算。