MyBatis注解开发实战:从基础CRUD到动态SQL与混合使用策略

发布时间:2026/9/20 1:55:25

MyBatis注解开发实战:从基础CRUD到动态SQL与混合使用策略 1. 从XML到注解为什么我选择在项目中混合使用如果你和我一样是从MyBatis的XML配置时代一路走过来的开发者那么第一次看到满篇的Select、Insert注解时心里多半会犯嘀咕这玩意儿能行吗XML多清晰啊SQL和Java代码分离维护起来也方便。我最初也是这么想的直到在一个快速迭代、需求频繁变动的内部工具项目中我被XML文件之间来回切换和繁琐的namespaceid匹配搞得有点烦躁才决定认真试试注解开发。几年用下来我的结论是MyBatis的注解开发绝不是为了取代XML而是一种强有力的补充和特定场景下的最优解。它特别适合那些SQL逻辑相对简单、变动频繁、或者你希望DAO层接口能“自成一体”、减少文件跳转的场合。比如管理后台的CRUD接口、简单的报表查询、或者是一些原型验证阶段的功能。当你看到一个接口方法同时就能看到它要执行的SQL这种“所见即所得”的体验在开发调试阶段效率提升非常明显。当然网上很多教程只告诉你注解怎么用却很少说清楚什么时候用、用了有什么坑。这篇内容我就结合自己趟过的路把MyBatis注解开发从入门到进阶再到生产环境下的混合使用策略掰开揉碎了讲清楚。我们会涵盖基础的CRUD、复杂的结果映射、动态SQL、以及二级缓存等核心主题目标就是让你看完后不仅能写出注解代码更能做出合适的技术选型。2. 环境搭建与基础CRUD注解实战开始写注解之前得先把场子搭起来。这里假设你已经在用Spring Boot整合MyBatis无非就是加依赖、配数据源。关键点在于要确保MyBatis能扫描到你的Mapper接口。2.1 核心依赖与配置要点在你的pom.xml里需要的是mybatis-spring-boot-starter。版本选择上我建议直接上较新的稳定版比如3.0.x以上。新版本对注解的支持更完善也修复了不少历史遗留问题。dependency groupIdorg.mybatis.spring.boot/groupId artifactIdmybatis-spring-boot-starter/artifactId version3.0.3/version !-- 示例版本请使用最新稳定版 -- /dependency dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId scoperuntime/scope /dependency在application.yml中基础的数据库配置必不可少。但关于MyBatis本身有一个配置项对注解开发至关重要mybatis: configuration: map-underscore-to-camel-case: true # 强烈建议开启下划线转驼峰省去大量Result映射开启这个配置后数据库字段user_name会自动映射到Java实体属性userName上对于简单的查询你甚至可以不写任何Result映射非常省事。这是很多新手会忽略的一个高效技巧。2.2 核心CRUD注解逐一看假设我们有一个User实体和对应的UserMapper接口。下面我们看最常用的四个注解。Select查询的基石Mapper public interface UserMapper { Select(SELECT id, user_name, age, email FROM user WHERE id #{id}) User selectById(Long id); Select(SELECT * FROM user WHERE age #{minAge}) ListUser selectByMinAge(Integer minAge); }注意SELECT *在注解里要谨慎使用。如果数据库表字段顺序或数量发生变化而你的实体类没及时更新可能会导致映射错误。显式列出字段是更稳妥的做法尤其是在生产环境。Insert插入数据与返回主键插入操作简单但如何获取数据库生成的主键比如自增ID是个关键点。Insert(INSERT INTO user (user_name, age, email) VALUES (#{userName}, #{age}, #{email})) Options(useGeneratedKeys true, keyProperty id) // 关键在这里 int insertUser(User user);Options注解的useGeneratedKeys true告诉MyBatis使用JDBC的getGeneratedKeys方法来获取数据库生成的主键。keyProperty id指定将这个值回填到参数对象user的id属性中。执行完这个方法后user.getId()就能拿到插入的ID了。Update 与 Delete更新与删除这两个注解相对直接。Update(UPDATE user SET email #{email} WHERE id #{id}) int updateEmailById(Param(id) Long id, Param(email) String email); Delete(DELETE FROM user WHERE id #{id}) int deleteById(Long id);这里引入了Param注解。当方法有多个参数时你必须使用Param给每个参数命名在SQL中通过#{参数名}来引用。如果只有一个参数且是基本类型/String可以不用Param但为了清晰我习惯都加上。2.3 关于Param注解的深度理解Param的作用不仅仅是解决多参数问题。它本质上是为参数创建了一个在SQL上下文中可用的名字。即使你只有一个复杂对象参数有时也需要它。// 场景模糊查询参数是一个User对象但我们只想用其中的name属性进行模糊匹配 Select(SELECT * FROM user WHERE user_name LIKE CONCAT(%, #{user.name}, %)) ListUser selectByUserCondition(Param(user) User user);如果没有Param(user)在SQL中直接写#{name}是取不到值的因为MyBatis不知道name属性属于哪个参数对象。通过Param指定后就可以用#{user.name}这种OGNL表达式来访问对象属性了。这是处理复杂查询条件时的一个实用模式。3. 解决复杂映射Results与ResultMap基础CRUD的SQL简单映射也简单。但遇到查询结果包含关联对象、集合或者字段名与属性名无法通过驼峰规则自动映射时就需要Results和ResultMap出场了。3.1 处理字段名不对应与简单关联假设我们查询用户及其所属部门假设部门信息在user表中有dept_id和dept_name字段但实体类中是deptId和deptName。Select(SELECT u.id, u.user_name, u.dept_id, d.name as dept_name FROM user u LEFT JOIN department d ON u.dept_id d.id WHERE u.id #{id}) Results({ Result(column id, property id, id true), // idtrue表示这是主键 Result(column user_name, property userName), Result(column dept_id, property deptId), Result(column dept_name, property deptName) }) User selectUserWithDeptById(Long id);Results注解可以理解为一个结果映射的集合。Result中的column是数据库查询结果的列名或别名property是Java实体类的属性名。当开启了map-underscore-to-camel-case后像user_name到userName的映射其实可以省略但这里为了演示完整性还是写了出来。对于主键建议明确标记id true这有助于提高性能尤其是在嵌套查询时。3.2 使用ResultMap复用映射规则如果同一个映射规则在多个Select方法中都要用到每次都写一遍Results太冗余了。这时可以用ResultMap。首先在一个方法上定义Results并指定一个唯一的idSelect(SELECT * FROM user WHERE id #{id}) Results(id userResultMap, value { Result(column id, property id, id true), Result(column user_name, property userName), Result(column dept_id, property deptId) }) User selectByIdForMap(Long id);然后在其他方法中通过ResultMap来引用这个映射规则Select(SELECT * FROM user WHERE age #{age}) ResultMap(userResultMap) // 直接复用上面定义的映射 ListUser selectByAge(Integer age);这种方式极大地减少了重复代码。但请注意ResultMap引用的id必须在同一个Mapper接口内定义。它无法跨Mapper接口引用这是注解开发的一个局限性。3.3 一对多、多对一关联映射的挑战与方案这是注解开发最棘手的部分之一。在XML中我们可以使用collection和association轻松定义复杂关联。在注解中MyBatis提供了One和Many注解来模拟但用起来颇为繁琐。例如查询用户及其所有订单一对多。// OrderMapper.java Mapper public interface OrderMapper { Select(SELECT * FROM order WHERE user_id #{userId}) ListOrder selectByUserId(Long userId); } // UserMapper.java Select(SELECT * FROM user WHERE id #{id}) Results({ Result(id true, column id, property id), Result(column user_name, property userName), Result(column id, property orderList, // 将用户id作为参数传递给另一个查询 many Many(select com.example.mapper.OrderMapper.selectByUserId)) }) User selectUserWithOrders(Long id);Many注解的select属性指定了另一个Mapper方法的全限定名或同一Mapper内的方法名。MyBatis会先执行主查询SELECT * FROM user然后对每一条结果再执行一次OrderMapper.selectByUserId(user.id)最后将查询到的ListOrder集合设置到User对象的orderList属性中。这种方式的优缺点非常明显优点逻辑清晰直接利用已有的Mapper方法符合SQL直观思维。缺点容易产生N1查询问题。如果主查询返回10个用户那么就会产生1主查询10查询订单11次数据库查询性能隐患巨大。对于数据量大的场景这是不可接受的。因此对于复杂的关联查询我个人的强烈建议是不要在注解里硬扛回归XML写一个联表查询才是正道。你可以用Select注解执行一个联表查询SQL然后通过Results手动映射每一个字段包括嵌套对象的字段但这会让Results变得极其庞大和难以维护。此时XML的清晰和强大就体现出来了。这也引出了我的核心观点注解与XML混合使用各取所长。4. 注解下的动态SQLProvider与
延伸阅读

更多相关文章

2026/9/20 10:08:53

可制造性设计(DFM)核心挑战与全流程实践指南

1. 从“画得出来”到“造得出来”:可制造性设计的核心挑战在硬件产品开发领域,有一个让无数工程师和项目经理头疼不已的经典困境:实验室里功能完美、性能惊艳的样机,一旦进入量产阶段,要么良率惨不忍睹,要么…

2026/9/20 15:02:05

终极免费网盘直链下载助手:八大平台高速下载完全指南

终极免费网盘直链下载助手:八大平台高速下载完全指南 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼云…

2026/9/20 1:55:34

PICAXE编程进阶:从输入输出到项目实战的嵌入式系统开发指南

1. 项目概述:从入门到实践,解锁PICAXE编程的核心技能上次我们聊了PICAXE编程的入门,搭建了环境,点亮了第一个LED,算是和这个小家伙打了个招呼。很多朋友反馈说,感觉像是刚拿到驾照,只会直行和倒…

2026/9/20 15:00:54

绿色免费工控软件Tansen2.3.4L应用支持MODBUS-RTU协议

Tansen 2.3.4L是最新版绿色免费的工控软件,该软件可支持modbus(rut) 协议的各种设备,作为上位机软件使用。应用于设备组组成系统,实现集中显示、控制、数据记录、定时、历史数据查找等功能。下面介绍软件的下载,安装,使…

2026/9/20 15:00:54

雅思练习总结(三十八)

雅思练习总结(三十八) 本文章是雅思练习总结(三十八),总结了文章《AIR TRAFFIC CONTROL IN THE USA》,内容包括原文精翻,文章脉络总结,单词扩展学习3个部分 1 文章原文及翻译 AIR TR…

2026/9/20 15:00:54

猫抓插件怎么用:浏览器下载网页视频与资源嗅探完整教程

猫抓插件怎么用:浏览器下载网页视频与资源嗅探完整教程 【免费下载链接】cat-catch 猫抓 浏览器资源嗅探扩展 / cat-catch Browser Resource Sniffing Extension 项目地址: https://gitcode.com/GitHub_Trending/ca/cat-catch 网页上的视频明明就在播放&…

2026/9/20 15:00:54

UI-TARS 桌面版:5 分钟从安装到跑通 AI GUI 自动化

UI-TARS 桌面版:5 分钟从安装到跑通 AI GUI 自动化 【免费下载链接】UI-TARS-desktop The Open-Source Multimodal AI Agent Stack: Connecting Cutting-Edge AI Models and Agent Infra 项目地址: https://gitcode.com/GitHub_Trending/ui/UI-TARS-desktop …

2026/9/20 14:55:53

用pypdf和pytest将微软面试100题整理成可复现复习仓库

简介:微软面试100题(含参考答案)是一份面向程序员与技术岗求职者的经典面试题库,特别适合准备微软、谷歌、百度等科技公司算法与数据结构面试的读者。压缩包共1个PDF文件,大小3.16MB,内容组织清晰&#xff…

2026/9/20 0:04:49

GAMP 5 基于风险的计算机化系统验证:软件分类与审计追踪实践

简介:《A Risk-Based Approach to Compliant GxP Computerized Systems》即业内熟知的GAMP 5指南,面向制药企业质量与IT合规人员、验证工程师及计算机化系统管理者,用于解决GxP法规环境下系统合规性难以科学落地的问题。文档以风险管理为主线…

2026/9/20 0:04:49

安全托管MSSP实战:从静态防御到人机协同的攻防运营与应急响应

简介:这份PPT围绕互联网业务安全托管服务展开,面向企业安全负责人、IT运维人员及关注MSSP/MSS选型的读者,重点回应传统安全过度依赖人工、碎片化静态防御难以对抗产业化攻击等痛点。资源共1个pptx文件,包体约30.63MB,以…

2026/9/20 0:04:49

GAMP 5 基于风险的计算机化系统验证:软件分类与审计追踪实践

简介:《A Risk-Based Approach to Compliant GxP Computerized Systems》即业内熟知的GAMP 5指南,面向制药企业质量与IT合规人员、验证工程师及计算机化系统管理者,用于解决GxP法规环境下系统合规性难以科学落地的问题。文档以风险管理为主线…

2026/9/20 0:04:49

安全托管MSSP实战:从静态防御到人机协同的攻防运营与应急响应

简介:这份PPT围绕互联网业务安全托管服务展开,面向企业安全负责人、IT运维人员及关注MSSP/MSS选型的读者,重点回应传统安全过度依赖人工、碎片化静态防御难以对抗产业化攻击等痛点。资源共1个pptx文件,包体约30.63MB,以…

2026/9/20 4:54:47

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/20 5:01:23

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/20 5:09:33

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码