150 行代码,吊打 MyBatis 全家桶

发布时间:2026/7/29 6:37:46
150 行代码,吊打 MyBatis 全家桶 150 行代码吊打 MyBatis 全家桶联表才是真实战场ORM 却在那儿卷单表先说结论两个层次一次说清这篇文章有两个层次150 行核心代码直接干翻原生 MyBatisXML 映射 动态 SQL 分页插件。基于这 150 行构建的Spring JDBC UltraSimpleDAO框架全面碾压MyBatis 全家桶MyBatis PageHelper MyBatis-Plus 各类插件。更致命的是所有 ORM 框架都在疯狂内卷单表那玩意只占真实业务 10% 都不到而Spring JDBC Ultra 的主战场从一开始就是联表——那 90% 的真实业务场景。第一层150 行代码干翻原生 MyBatis原生 MyBatis 最引以为傲的卖点是什么动态 SQL 物理分页。我们用 150 行纯 Java Spring JDBC 代码把这俩活干得明明白白。1. BaseCondition —— 动态条件的终极封装约 50 行publicabstractclassBaseCondition{GetterSetterprivateIntegersize10;GetterSetterprivateIntegerpage1;protectedListObjectparamListnewArrayList();protectedStringBuilderconditionnewStringBuilder();protectedabstractvoidaddCondition();publicStringwhere(){condition.setLength(0);paramList.clear();addCondition();Stringcondcondition.toString();returncond.isEmpty()?:cond.replaceFirst(AND,WHERE);}publicObject[]array(){returnparamList.toArray();}protectedfinalvoidand(Stringsql,Objectvalue){if(Objects.nonNull(value)StringUtils.hasText(value.toString())){condition.append( sql);paramList.add(value);}}protectedfinalvoidin(Stringsql,Object[]values){if(!ObjectUtils.isEmpty(values)){condition.append( sql).append(in(values));paramList.addAll(Arrays.asList(values));}}protectedfinalvoidand(Stringsql,Stringvalue,intsite){if(StringUtils.hasText(value)){condition.append( sql);paramList.add(site1?%value:site2?value%:%value%);}}privatestaticStringin(Object...ids){returnString.format((%s),String.join(,,Collections.nCopies(ids.length,?)));}}2. BaseDao —— 白盒分页约 40 行publicclassBaseDaoT{AutowiredprotectedJdbcTemplatejdbc;protectedCextendsBaseConditionPageTpage(Stringsql,Ccond,ClassTclazz){// 查总数就是子查询套个 COUNTStringcountSqlSELECT COUNT(1) FROM (sqlcond.where()) t;Integercountjdbc.queryForObject(countSql,Integer.class,cond.array());// 查数据就是 LIMIT offset, sizeintoffset(cond.getPage()-1)*cond.getSize();ListTdatajdbc.query(sqlcond.where() LIMIT offset,cond.getSize(),newBeanPropertyRowMapper(clazz),cond.array());returnnewPage(data,cond.getSize(),count,cond.getPage());}}3. 使用示例约 20 行SetterGetterBuilderpublicclassUserCondextendsBaseCondition{privateStringname;privateIntegerageMin;privateIntegerageMax;OverrideprotectedvoidaddCondition(){and(name LIKE ?,name,3);// 全模糊and(age ?,ageMin);and(age ?,ageMax);}}RepositorypublicclassUserDaoextendsBaseDaoUser{publicPageUserpageQuery(UserCondcond){StringsqlSELECT * FROM sys_user;returnpage(sql,cond,User.class);}}原生 MyBatis 做同样的事要写Mapper 接口1 个文件XML 映射文件selectwhereif至少 10 行依赖 PageHelper 插件引入依赖 配置拦截器分页时调用PageHelper.startPage()底层用反射篡改BoundSql而我们150 行纯 Java 代码无 XML、无拦截器、无反射动态条件用 Java 的if判断分页用LIMIT算术。谁更透明谁更可控谁更容易调试结论原生 MyBatis 的“动态 SQL 分页”王牌被这 150 行代码按在地上摩擦。第二层Spring JDBC Ultra吊打 MyBatis 全家桶如果说 150 行代码干翻的是“原生 MyBatis”那么基于它构建的Spring JDBC Ultra即 SimpleDAO框架则直接掀翻了MyBatis 全家桶。1. 单表 CRUD 审计 逻辑删除零 XMLDataTable(sys_user)publicclassUser{IdprivateLongid;privateStringname;privateIntegerage;privateStringphone;privateLocalDateTimecreateTime;privateLongcreateBy;privateIntegerdr;// 逻辑删除}RepositorypublicclassUserDaoextendsBaseDaoUser{// 无需任何代码继承即拥有 save、update、delete、findById、page 等全套能力}2. 联表查询——这才是主战场约 20 行RepositorypublicclassOrderDaoextendsBaseDaoOrder{// 联表 SQL 直接写完整不用拆成 XML 碎片privatestaticfinalStringSQLSELECT t.*, u.name user_name, u.phone user_phone, u.email user_email FROM bus_order t LEFT JOIN sys_user u ON t.user_id u.id;// 分页 联表同一套 APIpublicPageOrderVOpageJoin(OrderCondcond){returnpage(SQL,cond,OrderVO.class);}}关键点page(SQL, cond, OrderVO.class)单表分页是这个方法联表分页也是这个方法API 完全统一OrderVO extends OrderVO 继承实体联表字段userName、userPhone自动映射复杂条件子查询、IN、范围全在OrderCond里一次性搞定MyBatis-Plus 遇到联表查询就得退回 XML 写resultMapassociation而 Ultra 从头到尾只有一种写法原生 SQL。3. 三表联查 复杂条件约 30 行RepositorypublicclassGoodsDaoextendsBaseDaoGoods{privatestaticfinalStringSQLSELECT t.id goods_id, t.goods_name, t.price, o.id order_id, o.order_no, u.id user_id, u.name user_name, u.age FROM bus_goods t JOIN bus_order o ON t.order_id o.id AND o.dr 0 JOIN sys_user u ON o.user_id u.id AND u.dr 0;publicListGoodsVolistJoin(GoodsCondcond){returnlist(SQL,cond,GoodsVo.class);}}publicclassGoodsCondextendsBaseCondition{privateStringuserName;privateLocalDateTimecreateTimeStart;privateLocalDateTimecreateTimeEnd;privateObject[]goodsNames;OverrideprotectedvoidaddCondition(){and(u.name LIKE ?,userName,3);and(o.create_time ?,createTimeStart);and(o.create_time ?,createTimeEnd);// 子查询 IN 条件if(ArrayUtils.isNotEmpty(goodsNames)){add(AND o.id IN (SELECT order_id FROM bus_goods WHERE goods_name IN,goodsNames);add(AND dr0));}}}这个三表联查 子查询 IN 条件的组合在 MyBatis-Plus 的 LambdaWrapper 里根本写不出来只能退 XML。而 Ultra 用 Java 的if 字符串拼接就搞定了断点随便打SQL 肉眼可见。4. 报表聚合GROUP BY 聚合函数publicListReportGoodsVoreportGoods(ReportCondcond){StringsqlSELECT t.goods_name, COUNT(o.id) order_count, SUM(t.price) total_amount FROM t_goods t JOIN t_order o ON t.order_id o.id cond.where() GROUP BY t.goods_name;returnlist(sql,ReportGoodsVo.class,cond.array());}MyBatis 的 XML 里写 GROUP BY 没问题但一旦需要动态条件组合又得if满天飞。Ultra 的cond.where()一行搞定。5. 数据权限AOP 透明注入约 20 行AspectComponentpublicclassDataAuthAspect{Before(annotation(auth))publicvoidbeforeQuery(JoinPointpoint,DataAuthauth){BaseConditioncond(BaseCondition)point.getArgs()[0];StringuserIdrequest.getHeader(X-User-Id);cond.setExtendCondition( AND auth.userField() IN (userId,0));}}使用时只需在 DAO 方法上加注解DataAuth(userFieldt.receiver)publicPageNoticeVOpageJoin(NoticeCondcond){...}MyBatis 的数据权限需要写拦截器钻黑盒、解析BoundSql、反射修改Ultra 直接在 AOP 里拼字符串程序员 10 分钟写完。6. 数据脱敏AOP 后置处理约 30 行Desensitize(types{phone,idCard},fields{phone,idCard})publicListUserlist(UserCondcond){returnuserDao.list(cond);}MyBatis 做脱敏要么在 SQL 层用函数影响索引要么在业务层循环处理Ultra 用 AOP 统一收口干净利落。ORM 的内卷卷错了地方JPA/Hibernate卷单表继承、卷懒加载、卷一级缓存。一遇到联表立马崩塌。MyBatis-Plus卷 LambdaWrapper、卷自动填充、卷逻辑删除。一遇到联表LambdaWrapper 全废退回 XML。它们在这个占了 90% 的“联表战场”上没有任何优势。《真相系列・第7集》里写得极其精准“真实的企业级开发中单表场景占比远不到 10%。企业开发的核心是多表联动——权限、统计、业务流程落地都需要多表联查。所谓‘单表解决 80% 业务’只是掩盖框架在复杂场景下的短板。”而 Spring JDBC Ultra 的主战场从来都是联表——因为它的 SQL 是手写的、完整的、可视的没有任何中间层篡改或阉割 SQL 能力。终极对比能力维度MyBatis 全家桶Spring JDBC Ultra动态 SQLXMLif OGNLJavaifStringBuilder分页PageHelper 反射篡改BoundSql4 行算术LIMIT单表 CRUDMyBatis-Plus 自动生成BaseDao继承即得联表查询MP 废掉退回 XML原生 SQL直接执行三表联查 子查询 IN几乎不可维护统一 API一行搞定报表聚合XML 标签地狱原生 SQL 条件复用数据权限拦截器黑盒 反射AOP 切面拼 SQL脱敏复杂配置或手动循环AOP 后置统一处理异常定位堆栈深难溯源直指JdbcTemplate调用学习成本XML OGNL 插件 API会 Spring JDBC 即可最终结论150 行核心代码用最原始、最透明的方式把原生 MyBatis 赖以生存的“动态 SQL 分页”连根拔起。Spring JDBC Ultra 框架在 150 行基础上补充了单表 CRUD、联表、三表联查、子查询、报表、数据权限、脱敏等全套能力。ORM 框架在 10% 的单表战场上拼命内卷却在 90% 的联表战场上缴械投降。Ultra 从一开始就主攻联表——因为这才是真实世界的开发常态。MyBatis 的“生态”不过是补丁堆砌而 Ultra 从第一天起就建立在 Spring JDBC 的钢铁骨架上没有黑盒没有反射没有中间商。你问我底气哪儿来的底气是 Spring JDBC 给的是几十年来无数生产环境验证过的透明和稳定给的。MyBatis 的粉丝他们的底气是“赌”——赌插件不崩、赌版本兼容、赌反射不改坏。这不是底气是运气。相关开源地址核心框架源码https://gitee.com/gao_zhenzhong/simple-dao系统底座Spring Boot Starterhttps://gitee.com/gao_zhenzhong/simple-dao-starter代码生成器全栈https://gitee.com/gao_zhenzhong/simple-dao-coder实战案例本文全部源码https://gitee.com/gao_zhenzhong/simple-dao-demo全文完。所有论证基于纯逻辑推导和实际可运行的代码不依赖任何营销话术。欢迎 Clone 项目亲自验证。

相关新闻

最新新闻

日新闻

周新闻

月新闻