发布时间:2026/8/4 3:48:00
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/8/4 3:48:00

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

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

2026/8/4 3:48:00

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

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

2026/8/4 4:48:03

从《英雄联盟》看现代军事装备的功能分类与战术价值

1. 项目背景与核心思路这个项目源于一个有趣的观察:电子游戏中的角色定位与现实军事装备之间存在某种微妙的对应关系。作为一名同时涉足游戏开发和军事装备研究的跨界从业者,我尝试从《英雄联盟》这款MOBA游戏的英雄分类视角,来解析现代战场装…

2026/8/4 4:48:03

Java开发环境搭建:从Oracle JDK到OpenJDK发行版的选型与实战指南

1. 从“下载JDK”到“选择JDK”:一个Java开发者的认知升级如果你刚接触Java,或者正准备搭建一个新的开发环境,你的第一反应很可能是:“去Oracle官网下载JDK”。这几乎是过去十年里Java开发者的一种肌肉记忆。但今天,这…

2026/8/4 4:48:03

Unicode编码原理与实战:从乱码解决到UTF-8应用

1. 从“乱码”到“统一”:为什么我们需要Unicode如果你在编程或者处理文本时,遇到过中文变成一堆问号“???”,或者特殊符号显示为“口口”,又或者在不同系统间传输文件后,原本好好的…

2026/8/4 4:48:03

2026年iOS短视频总结工具测评强识别提效率 整理清晰更省心

这次2026年iOS短视频总结工具测评里,我们发现听脑AI更适配HR群体整理面试记录、OKR面谈、人事决策内容的需求,核心优势是转写速度快,支持多语言和多方言识别,结构化整理能力突出,适合需要高频整理录音的HR,…

2026/8/4 4:43:03

SpringBoot全栈校园视频系统开发实践

1. 项目概述与核心价值校园视频系统作为数字化校园建设的重要组成部分,正在成为高校信息化基础设施的标配。这个基于SpringBoot的全栈项目,不仅提供了完整的视频资源管理功能,更通过前后端分离架构实现了高效的内容分发。我在实际开发中发现&…

2026/8/3 21:14:30

如何用免费工具突破游戏窗口限制:SRWE完整使用指南

如何用免费工具突破游戏窗口限制:SRWE完整使用指南 【免费下载链接】SRWE Simple Runtime Window Editor 项目地址: https://gitcode.com/gh_mirrors/sr/SRWE 你是否遇到过这样的困扰?想为心爱的游戏截图,却发现游戏不支持自定义分辨率…

2026/8/4 0:02:01

dealsea是什么?跨境卖家必知的美国deal站入门指南

说实话,第一次听说美国这个老牌折扣网站的跨境卖家,十个有八个会问同一个问题:这个平台到底是干嘛的?我见过一个做家居出口的朋友,他在亚马逊上月销二十万美金,却从来没用过它。我给他看了首页——一屏一屏…

2026/8/3 22:40:58

实测才敢推 AI论文网站 2026最新测评与推荐

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。一、综…

2026/8/3 13:26:41

2026必备!AI论文网站测评:最新推荐与深度对比

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

2026/8/3 16:43:13

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…