当前位置: 首页 > news >正文

MyBatis 的注解式开发

MyBatis 的注解式开发是除了 XML 映射之外的另一种主流方式。它把 SQL 直接写在 Java 接口的方法上,省去了 XML 文件,适合简单查询和快速开发。

下面我从最基础的注解开始,逐步深入到复杂的映射和动态 SQL


一、为什么用注解式开发?

维度注解式XML 式
代码密度高(SQL 和 Java 在同一文件)低(需要单独维护 XML)
可读性简单查询清晰复杂查询更易读
动态 SQL较复杂(用@SelectProvider非常灵活(<if><where>
维护成本低(修改接口即改 SQL)中等(需同时维护接口和 XML)
适用场景简单 CRUD、快速开发复杂联表查询、动态条件多

结论:没有绝对的优劣,实际项目中通常是注解和 XML 混合使用,简单查询用注解,复杂查询用 XML。


二、基础 CRUD 注解

1.@Select/@Insert/@Update/@Delete

publicinterfaceUserMapper{// 查询单条@Select("SELECT * FROM user WHERE id = #{id}")UserselectById(Longid);// 查询列表@Select("SELECT * FROM user WHERE name LIKE CONCAT('%', #{name}, '%')")List<User>selectByName(Stringname);// 插入,使用 @Options 返回自增主键@Insert("INSERT INTO user(name, age, email) VALUES(#{name}, #{age}, #{email})")@Options(useGeneratedKeys=true,keyProperty="id")intinsert(Useruser);// 更新@Update("UPDATE user SET name = #{name}, age = #{age} WHERE id = #{id}")intupdate(Useruser);// 删除@Delete("DELETE FROM user WHERE id = #{id}")intdeleteById(Longid);}

2. 返回自增主键

使用@Options(useGeneratedKeys = true, keyProperty = "id"),插入后 MyBatis 会自动把生成的主键设置到对象的id属性中。

Useruser=newUser();user.setName("张三");userMapper.insert(user);System.out.println("新插入的ID:"+user.getId());// 自动回填

三、参数传递

1. 单个参数(基本类型)

直接用#{参数名}即可。

@Select("SELECT * FROM user WHERE id = #{id}")UserselectById(Longid);

2. 多个参数——使用@Param

多个参数时,必须用@Param注解给参数起别名。

@Select("SELECT * FROM user WHERE name LIKE CONCAT('%', #{name}, '%') AND age > #{age}")List<User>selectByNameAndAge(@Param("name")Stringname,@Param("age")Integerage);

如果没有@Param,MyBatis 会用arg0arg1或者param1param2作为参数名,非常不直观。

3. 传入 POJO 对象

直接用#{属性名}即可,MyBatis 会自动读取对象的 getter 方法。

@Insert("INSERT INTO user(name, age, email) VALUES(#{name}, #{age}, #{email})")intinsert(Useruser);

4. 传入 Map

@Select("SELECT * FROM user WHERE name = #{name} AND age = #{age}")List<User>selectByMap(Map<String,Object>params);

调用时:

Map<String,Object>map=newHashMap<>();map.put("name","张三");map.put("age",25);userMapper.selectByMap(map);

四、结果映射——@Results@Result

当数据库字段名和 Java 属性名不一致时,需要手动映射。

@Select("SELECT id, user_name, user_age FROM user WHERE id = #{id}")@Results(id="userResultMap",value={@Result(column="id",property="id"),@Result(column="user_name",property="name"),@Result(column="user_age",property="age")})UserselectById(Longid);

@Resultsid属性可以给这个映射起一个名字,在其他方法中复用。

@Select("SELECT id, user_name, user_age FROM user")@ResultMap("userResultMap")// 复用上面的映射List<User>selectAll();

五、复杂关联查询——联表映射

1. 一对一关联(@One

publicclassUser{privateLongid;privateStringname;privateDeptdept;// 所属部门}// 查询用户时,顺便查询部门信息@Select("SELECT id, name, dept_id FROM user WHERE id = #{id}")@Results({@Result(column="id",property="id"),@Result(column="name",property="name"),@Result(column="dept_id",property="dept",one=@One(select="com.example.mapper.DeptMapper.selectById"))})UserselectUserWithDept(Longid);

2. 一对多关联(@Many

publicclassDept{privateLongid;privateStringname;privateList<User>users;// 部门下的所有用户}@Select("SELECT * FROM dept WHERE id = #{id}")@Results({@Result(column="id",property="id"),@Result(column="name",property="name"),@Result(column="id",property="users",many=@Many(select="com.example.mapper.UserMapper.selectByDeptId"))})DeptselectDeptWithUsers(Longid);

六、动态 SQL——@SelectProvider

注解方式处理动态 SQL(<if><where>等)比较麻烦,需要用@SelectProvider@InsertProvider等注解。

publicclassUserSqlProvider{publicStringselectByCondition(Map<String,Object>params){Stringname=(String)params.get("name");Integerage=(Integer)params.get("age");SQLsql=newSQL(){{SELECT("*");FROM("user");if(name!=null&&!name.isEmpty()){WHERE("name LIKE CONCAT('%', #{name}, '%')");}if(age!=null){WHERE("age > #{age}");}ORDER_BY("id DESC");}};returnsql.toString();}}// Mapper 中使用@SelectProvider(type=UserSqlProvider.class,method="selectByCondition")List<User>selectByCondition(Map<String,Object>params);

注意@SelectProvidermethod方法返回值必须是 String(即 SQL 语句)。


七、常用注解汇总

注解用途
@Select查询
@Insert插入
@Update更新
@Delete删除
@Options配置选项(如自增主键返回)
@Param参数命名
@Results/@Result结果字段映射
@One一对一关联查询
@Many一对多关联查询
@ResultMap复用已定义的@Results
@SelectProvider动态 SQL 提供者
@InsertProvider/@UpdateProvider/@DeleteProvider同上

八、注解 vs XML:如何选择?

场景推荐方式
单表 CRUD注解
简单联表查询(2-3张表)注解
复杂动态 SQL(多个<if><foreach>XML
5张表以上的复杂联表XML
需要复用 SQL 片段(<sql>XML
快速原型开发注解
大型项目、长期维护混合(注解+XML)

九、混合使用的配置方式

如果同时使用注解和 XML,MyBatis 会优先使用 XML(如果接口方法和 XML 中的 id 相同,XML 会覆盖注解)。更好的做法是明确区分:

  • 简单查询:注解写在接口方法上
  • 复杂查询:XML 写在对应的 Mapper XML 文件中,接口中只声明方法,不加注解
// 接口中不写 @Select,完全由 XML 接管publicinterfaceUserMapper{List<User>selectComplex(Map<String,Object>params);}
<!-- XML 文件中定义复杂 SQL --><selectid="selectComplex"resultType="User">SELECT * FROM user<where><iftest="name != null">name LIKE CONCAT('%', #{name}, '%')</if><!-- 更多复杂条件 --></where></select>

十、最佳实践建议

  1. 简单 CRUD 用注解,复杂查询用 XML,不要把注解搞得过于复杂。
  2. @Results一定要复用,通过id@ResultMap避免重复定义。
  3. 动态 SQL 超过 5 行时,果断用 XML,可读性更好。
  4. @Param不要省,哪怕只有一个参数也养成习惯,方便后期扩展。
  5. @SelectProvider适合复杂动态 SQL,但 SQL 构造逻辑建议单独放在一个类里,保持 Mapper 接口的干净。
http://www.cnnetsun.cn/news/4226832.html

相关文章:

  • 【TDengine】 TDengine 的内存管理模型是怎样的?缓存机制如何工作?
  • 【TDengine】TDengine 使用了哪些压缩算法?压缩率通常能达到多少?
  • 交叉编译零门槛:graphics.gd无需SDK构建Android、iOS与Web版Godot游戏
  • Video2X 完整上手:三步把模糊老视频放大到 4K、30fps 变 60fps
  • ArcGIS零起点实战教程|空间规划师必学GIS技能课(视频+数据包+工具集)
  • BlobRunner x64实现深度剖析:内联汇编为何失效,挂起线程如何救场
  • 记录C++ 11
  • 57-基于深度学习的农作物虫害检测识别系统(yolo26、yolo12、yolo11、yolov8、yolov5+UI界面+Python项目源码+模型+标注好的数据集)2027毕业版
  • OpenCV ncnn 人脸识别(一)
  • 如何部署AI模型到边缘端:keras_cv_attention_models TFLite转换完整指南(含3大常见坑)
  • 如何在org-trello中选择正确的同步方向?卡片级与缓冲区级同步完整指南
  • SAP UI5 里有没有 RxJS exhaustMap,答案不在某个 Operator,而在异步任务的并发控制方式
  • 从 clone 到登录:三十分钟用 Docker 部署 AzerothCore 魔兽世界私有服
  • C# Winform - SQL Server 2012 数据库放服务器,通过TCP连接访问
  • 如何用Dagger 2在Kotlin Android应用中实现依赖注入:基于PhotoAffix的完整教程
  • fb_graph认证全解析:Cookie解析与Signed Request的HMAC-SHA256验证原理指南
  • 为什么 Ornith-1.5-397B 效果忽好忽坏?temperature、top_p、top_k 采样参数调优完整指南
  • 5分钟上手psr/clock:从composer安装到第一个now()调用的快速教程
  • IntelliJ IDEA + phpStudy + ApiPost断点调试
  • 部署 FN-DSA 前:你必须了解的风险与权衡
  • 2026实测!梦琪科技拨号VPS排行,这3款性价比封神
  • 多模态模型也能当纯文本 LLM:InternVL3-2B-hf 无图文本生成快速入门
  • 公司电脑权限怎么管理?从账号、文件到软件,一套权限管理思路讲清楚
  • Status 拆解:19 天百万用户的 AI 社交模拟器如何炼成
  • Video2X AI 视频放大与补帧完整入门指南:从 480p 到 4K 成片
  • 华为MetaERP # EBS → Fusion BC 预算模块【业务规则对齐实施指南】定位:迁移蓝图「业务规则映射章节」标准内容,承接主数据映射、余额迁移、预算校验逻辑迁移。> > 核心结
  • PDF补丁丁:一个免费的PDF工具箱,搞定书签、合并、提图等8类编辑任务
  • 如何在React Native中使用react-timer-hook?移动App倒计时与秒表组件跨平台实战教程
  • 自己设计一道数独:LibreSudoku自定义出题功能完整流程演示
  • 基于SpringBoot的网购优选服务系统设计网站(源码+lw+部署文档+讲解等)