SpringData JPA 都能写 SQL,为啥还要用 MyBatis?

SpringData JPA 都能写 SQL,为啥还要用 MyBatis?

之前聊过JPA和MyBatis的核心区别,但总觉得没说透。实际开发里,很多人纠结选哪个,不是因为不知道“JPA面向对象、MyBatis面向SQL”,而是踩过具体的小坑后才明白——原来差的是这些细节。今天就从日常写代码的真实场景出发,把两者的差异拆得更细,再贴些实际用到的代码,看完你肯定能更清楚怎么选。

先从最基础的“字段映射”说起吧,这是每个项目都绕不开的。我认为JPA的映射看着方便,但遇到特殊场景就容易卡壳;MyBatis看似麻烦点,却能灵活应对各种奇葩表结构。

比如常见的“数据库字段和Java实体字段不一致”的情况。JPA里得用@Column注解指定列名,要是表字段有下划线(比如user_name),实体字段是驼峰(userName),还得在配置里开驼峰命名自动转换,或者每个字段都加@Column(name = “user_name”)。举个例子:

// JPA实体字段映射(应对下划线字段)@Entity@Table(name="t_user")// 表名和实体名不一致,得指定publicclassUser{@Id@GeneratedValue(strategy=GenerationType.IDENTITY)privateLongid;// 数据库字段是user_name,实体是userName,必须加注解@Column(name="user_name")privateStringuserName;// 数据库字段是create_time,开了驼峰转换才能不用注解privateLocalDateTimecreateTime;// getter/setter...}

要是遇到更特殊的,比如数据库里是varchar类型存的JSON字符串,实体里想直接用JSONObject接收。JPA就得自定义转换器,写个类实现AttributeConverter接口,再在字段上加@Convert注解,步骤不少。

但MyBatis处理这些就简单直接。字段映射可以在XML里用resultMap明确指定,哪怕字段名完全不一样,也能精准匹配,不用改实体类注解:

<!-- MyBatis XML 字段映射 --><resultMapid="UserResultMap"type="com.example.entity.User"><idcolumn="id"property="id"/><!-- 数据库user_name对应实体userName,直接指定 --><resultcolumn="user_name"property="userName"/><!-- 数据库create_time对应实体createTime,不用额外配置 --><resultcolumn="create_time"property="createTime"/><!-- JSON字符串转JSONObject,直接用TypeHandler --><resultcolumn="ext_info"property="extInfo"typeHandler="com.example.handler.JsonTypeHandler"/></resultMap><!-- 查询时指定resultMap即可 --><selectid="getUserById"resultMap="UserResultMap">SELECT id, user_name, create_time, ext_info FROM t_user WHERE id = #{id}</select>

在我看来,这种细节上的灵活度,就是很多人宁愿多写点SQL,也选MyBatis的原因——遇到奇葩表结构,不用跟框架“掰扯”,直接按自己的想法来就行。

再说说动态SQL,这也是日常开发高频场景。比如做一个列表查询,前端可能传用户名、状态、时间范围,也可能都不传,需要动态拼接WHERE条件。JPA和MyBatis都能做,但写起来的体验天差地别。

JPA里常用的是Specification或者JpaRepository的方法名派生。方法名派生只能应对简单条件,比如按用户名模糊查询+状态匹配,写个findByUserNameLikeAndStatus就行。但条件一多,方法名会变得巨长,比如findByUserNameLikeAndStatusAndCreateTimeBetweenAndDeptId,看着就头疼,后期改条件也容易写错。

用Specification会灵活点,但代码写起来很繁琐,尤其是多表关联的时候:

// JPA 用Specification做动态查询(用户名模糊+状态+时间范围)publicPage<User>queryUser(StringuserName,Integerstatus,LocalDateTimestartTime,LocalDateTimeendTime,Pageablepageable){returnuserRepository.findAll((root,query,cb)->{List<Predicate>predicates=newArrayList<>();// 用户名模糊查询if(StringUtils.isNotBlank(userName)){predicates.add(cb.like(root.get("userName"),"%"+userName+"%"));}// 状态匹配if(status!=null){predicates.add(cb.equal(root.get("status"),status));}// 时间范围if(startTime!=null&&endTime!=null){predicates.add(cb.between(root.get("createTime"),startTime,endTime));}// 拼接条件returncb.and(predicates.toArray(newPredicate[0]));},pageable);}

这段代码能跑,但读起来费劲,尤其是新人接手,得琢磨半天每个Predicate对应什么条件。而且多表关联时,root.join()的写法很容易出错,调试起来也麻烦。

再看MyBatis的动态SQL,直接在XML里用if、choose、where标签写,逻辑清晰,还能加注释,哪怕条件再多,也能看得明明白白:

<!-- MyBatis 动态SQL(和上面JPA同样的查询条件) --><selectid="queryUser"resultMap="UserResultMap">SELECT id, user_name, status, create_time FROM t_user<where><!-- 用户名模糊查询,非空才拼接 --><iftest="userName != null and userName !=''">AND user_name LIKE CONCAT('%', #{userName}, '%')</if><!-- 状态匹配,非空才拼接 --><iftest="status != null">AND status = #{status}</if><!-- 时间范围,两个都非空才拼接 --><iftest="startTime != null and endTime != null">AND create_time BETWEEN #{startTime} AND #{endTime}</if></where>ORDER BY create_time DESC LIMIT #{pageNum}, #{pageSize}</select>

我们的经验是,动态条件超过3个,用MyBatis写起来效率更高,后期维护也更省心。哪怕是新人,只要懂SQL,就能看懂这段XML里的逻辑,改条件的时候直接加个if标签就行,不用记JPA的各种API。

再聊个深入点的——多表关联查询。JPA的优势是能通过@OneToMany、@ManyToOne这些注解定义实体间的关联关系,查询的时候用fetch指定懒加载或急加载,就能自动关联查询出关联对象。比如查询用户的时候顺带查出用户的订单列表:

// JPA 多表关联(用户-订单 一对多)@EntitypublicclassUser{@IdprivateLongid;privateStringuserName;// 关联订单表,急加载@OneToMany(fetch=FetchType.EAGER)@JoinColumn(name="user_id")// 订单表的user_id关联用户表idprivateList<Order>orderList;// getter/setter...}// 查询用户时自动带出订单列表Useruser=userRepository.findById(1L).orElse(null);List<Order>orderList=user.getOrderList();// 直接获取,不用额外查询

这种写法看着方便,但坑也藏在这里。要是关联的表多,比如用户关联订单、订单关联商品、商品关联分类,JPA会生成一堆JOIN语句,甚至出现N+1查询问题(查1个用户带出N个订单,会执行1次查用户+N次查订单的SQL),性能直接拉胯。虽然能通过fetch join优化,但需要手动写JPQL,而且优化的度很难把握。

MyBatis处理多表关联,是手动写JOIN SQL,虽然要自己写关联条件,但能精准控制查询的字段和关联的表,避免冗余查询。比如同样查询用户和订单,只查需要的字段:

<!-- MyBatis 多表关联查询(用户+订单) --><resultMapid="UserWithOrderResultMap"type="com.example.entity.User"><idcolumn="user_id"property="id"/><resultcolumn="user_name"property="userName"/><!-- 关联订单列表 --><collectionproperty="orderList"ofType="com.example.entity.Order"><idcolumn="order_id"property="id"/><resultcolumn="order_no"property="orderNo"/><resultcolumn="amount"property="amount"/></collection></resultMap><selectid="getUserWithOrder"resultMap="UserWithOrderResultMap">SELECT u.id as user_id, u.user_name, o.id as order_id, o.order_no, o.amount FROM t_user u LEFT JOIN t_order o ON u.id = o.user_id WHERE u.id = #{id}</select>

这段SQL只查了需要的字段,没有多余的关联,执行效率更高。而且如果不需要订单列表,直接查用户表就行;需要的时候再写关联查询,灵活度拉满。要是遇到复杂的多表关联,还能拆分成多个简单查询,手动控制事务,比JPA的“黑盒优化”更让人放心。

最后再补充个细节——SQL的可调试性。JPA自动生成的SQL,有时候会很“奇葩”,比如字段名用奇怪的别名,排序逻辑不清晰。要是查询结果不对,想调试SQL都难,只能开启SQL日志,复制出来格式化后才能排查问题。

MyBatis就不一样了,写的SQL就是最终执行的SQL(除了动态拼接的部分),要是查询有问题,直接把XML里的SQL复制到数据库客户端,替换掉#{参数},执行一下就能定位问题。比如遇到查询结果为空,先在客户端跑SQL,看是条件错了还是字段错了,几分钟就能搞定,不用跟JPA的日志“较劲”。

总结下吧,我不是说JPA不好,它在标准CRUD、快速开发场景下确实香,适合领域模型清晰、SQL复杂度低的项目。但在细节把控上,比如字段映射、动态SQL、多表关联、性能优化,MyBatis的优势太明显了。

在我看来,选框架不是看哪个“高级”,而是看哪个更适配项目。如果是初创项目,追求快速上线,团队SQL能力一般,选JPA没问题;如果是中大型项目,有大量复杂查询,对性能要求高,或者需要DBA介入优化SQL,MyBatis绝对是更稳妥的选择。

现在很多项目都是“JPA+MyBatis”混着用,用JPA做简单的增删改查,用MyBatis处理复杂查询和报表。这种组合既能享受JPA的开发效率,又能拥有MyBatis的灵活度,算是兼顾效率和性能的最优解了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1199733.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

课本教不会的生存真相:那些值钱的核心能力,从来都藏在“额外付出”里

课本教不会的生存真相:那些值钱的核心能力,从来都藏在“额外付出”里 目录 课本教不会的生存真相:那些值钱的核心能力,从来都藏在“额外付出”里 打有把握的仗,提前搜集资料,通过LLM 学习通用方法 ,这个一般能超过常人 一、校园的“安全区”,藏着最隐蔽的能力鸿沟 二、…

Transformer 21问全解析:一文读懂核心原理

🚀 Transformer 21问全解析 目录 🚀 Transformer 21问全解析 1. Transformer为何使用多头注意力机制?(为什么不用一个头) 2. Transformer为什么Q和K使用不同的权重矩阵生成?为何不能用同一个值点乘? 3. Transformer计算attention时为何选点乘而不是加法?两者复杂度和…

2026年灵活用工平台:基于技术、合规、服务、性价比四大核心维度

前言:在数据时代,用标尺衡量灵活用工平台的专业度 随着2026年企业数字化转型进入深水区,供应商的筛选决策也越来越依赖客观数据与结构化分析。根据一项针对500家规模以上企业的采购决策调研显示,超过70%的受访者表…

基于单片机的血压计设计(有完整资料)

资料查找方式&#xff1a; 特纳斯电子&#xff08;电子校园网&#xff09;&#xff1a;搜索下面编号即可 设计编号&#xff1a; cj-51-2021-028 设计简介&#xff1a; 本设计家用便携式血压计的设计以血压为研究对象&#xff0c; 最终以STC89C52单片机为主控芯片&#xff0c…

基于Dify的RAG知识库搭建,大模型入门到精通,收藏这篇就足够了!

Dify 是一款开源的大模型应用开发平台&#xff0c;旨在帮助开发者快速构建生产级生成式 AI 应用。在Dify 本地化部署中&#xff0c;知识库功能是实现企业级 AI 应用的核心能力。 一、Dify基本概念 Dify 是一款开源的大模型应用开发平台&#xff0c;旨在帮助开发者快速构建生产…

基于单片机的音乐播放器的设计(有完整资料)

资料查找方式&#xff1a; 特纳斯电子&#xff08;电子校园网&#xff09;&#xff1a;搜索下面编号即可 编号&#xff1a; CJ-51-2021-029 设计简介&#xff1a; 本设计是基于单片机的音乐播放器&#xff0c;主要实现以下功能&#xff1a; 可实现LCD12864显示歌曲的名字和…

2026 年你必须了解的 10 大开源 AI Agent 框架

随着 AI agents 持续从研究概念演进为可投入生产的解决方案&#xff0c;开源框架正发挥关键作用&#xff0c;加速其落地。无论你在构建自主系统、基于 LLM 的应用&#xff0c;还是编排多智能体协作&#xff0c;选对 AI Agent 框架都至关重要。本文精选了 2025 年最值得关注的 1…

打破传统桎梏,LLM 让智能运维实现从 “自动化” 到 “自进化”

引言&#xff1a;复杂系统下的运维困境与LLM破局契机 在数字化浪潮的推动下&#xff0c;微服务、云原生、容器化等技术已深度融入软件系统的构建与运行全流程。这些技术的普及让系统功能更加强大、部署更加灵活&#xff0c;但同时也让系统架构变得愈发复杂。曾经单一服务器就能…

Java 接入 AI 大模型:从踩坑到高效落地

作为一名深耕 Java 开发多年的程序员&#xff0c;最近半年的核心任务是给公司现有业务系统接入 AI 大模型能力。原本以为只是简单调用接口&#xff0c;实际落地后才发现&#xff0c;Java 生态与 AI 大模型工具链之间&#xff0c;藏着不少容易被忽略的适配鸿沟。这段时间踩过的坑…

基于yolo13-C3k2-DBB的铝罐识别与分类平台

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

2026年GIS开发十大趋势

进入2026年&#xff0c;GIS早已不再是地图绘制的专属工具。它正深度融入数字孪生、智慧城市、自动驾驶、环境监测等前沿领域&#xff0c;成为驱动各行业数字化转型的核心引擎。本文将从技术、应用和产业三个维度&#xff0c;深入剖析2026年GIS开发的十大关键趋势&#xff0c;为…

第9章:MyBatis多级缓存和懒加载

文章目录第9章&#xff1a;MyBatis多级缓存和懒加载一级缓存二级缓存怎么使用懒加载第9章&#xff1a;MyBatis多级缓存和懒加载 一级缓存 什么是缓存&#xff1f; 一级缓存核心定位 一级缓存是 MyBatis 内置的 默认缓存机制&#xff0c;无需手动配置&#xff0c;默认开启。作…

Gemini 3超参数设置全攻略

通过 Api 调用gemini 3 的温度等超参数怎么设置 温度0.7 温度设置0.1 LLM 超参数介绍

全面覆盖!同城便民信息小程序源码系统,功能强大

温馨提示&#xff1a;文末有资源获取方式作为一款专注于多城市生活服务的同城便民信息小程序源码系统&#xff0c;全新升级版本带来了前所未有的功能整合和技术优化。该系统旨在满足现代人对便捷、高效生活服务的需求&#xff0c;通过一套源码即可轻松搭建一个功能完备的同城信…

基于STM32单片机PM2.5空气质量检测仪粉尘无线视频监控设计套件44(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_文章底部可以扫码

基于STM32单片机PM2.5空气质量检测仪粉尘无线视频监控设计套件44(设计源文件万字报告讲解)&#xff08;支持资料、图片参考_相关定制&#xff09;_文章底部可以扫码 STM32单片机PM2.5空气质量检测雾霾检测除尘系统44产品功能描述&#xff1a; 本系统由STM32F103C8T6单片机核心板…

技术领先!多用户同城小程序源码系统 带完整的搭建部署教程

温馨提示&#xff1a;文末有资源获取方式 在信息爆炸的时代&#xff0c;一款基于先进技术的同城便民信息小程序源码系统应运而生&#xff0c;全新版本以多用户无限账户为核心&#xff0c;为创业者提供前所未有的机会。该系统专注于多城市生活服务&#xff0c;通过灵活的技术架构…

2026年知名的服务器公司哪家专业?高性价比品牌排行

在2026年的服务器市场中,选择一家专业且高性价比的供应商需要综合考虑技术实力、定制能力、生产规模、行业口碑和价格竞争力。经过对行业发展趋势和实际用户反馈的分析,我们推荐以下五家各具特色的服务器供应商,其中…

【直播预告】 复刻高德地图导航——GIS开发实战直播来袭!

如果你希望掌握WebGIS开发的核心技能&#xff0c;提升自己在GIS领域的竞争力。本周四下午2点&#xff0c;我们将带来一场适合webgis小白学习的技术直播&#xff0c;使用Vue框架开发高德地图的导航功能。适合人群&#xff1a;对GIS开发感兴趣、想从事地图开发的学生/在职人员。无…

零基础入门指南,如何利用酒店预订系统源码快速开展数字业务

温馨提示&#xff1a;文末有资源获取方式面对酒店行业日益增长的线上化需求&#xff0c;许多非技术出身的创业者或中小酒店业主感到无从下手。市场上出现的一款一体化酒店预订小程序源码系统&#xff0c;完美解决了这一痛点。它被誉为“技术小白也能驾驭的创业利器”&#xff0…

基于STM32单片机恒温箱K型热电偶工业锅炉温度无线APP设计套件16(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_文章底部可以扫码

基于STM32单片机恒温箱K型热电偶工业锅炉温度无线APP设计套件16(设计源文件万字报告讲解)&#xff08;支持资料、图片参考_相关定制&#xff09;_文章底部可以扫码STM32单片机智能热电偶工业锅炉温度控制恒温箱16 产品功能描述&#xff1a; 本系统由STM32F103C8T6单片机核心板、…