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

MyBatis常用注解全解析:从基础CRUD到高级映射

MyBatis常用注解全解析:从基础CRUD到高级映射

本文全面解析MyBatis核心注解体系,涵盖基础操作、动态SQL、关系映射等高级特性,助你彻底掌握MyBatis注解开发精髓

一、MyBatis注解概述

1.1 注解 vs XML配置

MyBatis同时支持XML配置注解两种方式实现SQL映射:

特性XML配置注解
可读性高(SQL与Java分离)中(SQL嵌入代码)
维护性修改无需重新编译修改需重新编译
灵活性支持复杂动态SQL动态SQL有限
简洁性文件较多零配置
适用场景大型复杂项目中小型项目/快速开发

1.2 注解核心优势

  1. 零配置快速启动:无需XML文件
  2. 接口与SQL紧耦合:SQL直接定义在DAO接口
  3. 类型安全:编译时检查SQL语法
  4. 简化开发:减少文件切换

二、基础CRUD注解

2.1 @Select:查询操作

@Select("SELECT * FROM users WHERE id = #{id}")
User getUserById(@Param("id") int id);// 多参数查询
@Select("SELECT * FROM users WHERE name = #{name} AND age > #{age}")
List<User> findUsers(@Param("name") String name, @Param("age") int age);// 返回Map
@Select("SELECT id, name FROM users")
@MapKey("id")
Map<Integer, User> getUserMap();

高级特性

  • 支持结果映射(配合@Result/@Results)
  • 支持动态SQL(配合

2.2 @Insert:插入操作

// 返回自增主键
@Insert("INSERT INTO users(name, email) VALUES(#{name}, #{email})")
@Options(useGeneratedKeys = true, keyProperty = "id")
int insertUser(User user);// 批量插入
@Insert({"<script>","INSERT INTO users (name, email) VALUES","<foreach collection='list' item='user' separator=','>","(#{user.name}, #{user.email})","</foreach>","</script>"
})
int batchInsertUsers(@Param("list") List<User> users);

2.3 @Update:更新操作

@Update("UPDATE users SET name=#{name}, email=#{email} WHERE id=#{id}")
int updateUser(User user);// 条件更新
@Update({"<script>","UPDATE users","<set>","  <if test='name != null'>name=#{name},</if>","  <if test='email != null'>email=#{email},</if>","</set>","WHERE id=#{id}","</script>"
})
int updateUserSelective(User user);

2.4 @Delete:删除操作

@Delete("DELETE FROM users WHERE id = #{id}")
int deleteUser(int id);// 批量删除
@Delete({"<script>","DELETE FROM users WHERE id IN","<foreach item='id' collection='ids' open='(' separator=',' close=')'>","#{id}","</foreach>","</script>"
})
int deleteUsersByIds(@Param("ids") List<Integer> ids);

三、结果映射注解

3.1 @Results与@Result

@Results(id = "userResultMap", value = {@Result(property = "id", column = "id", id = true),@Result(property = "name", column = "user_name"),@Result(property = "email", column = "user_email"),@Result(property = "createTime", column = "create_time", typeHandler = LocalDateTimeTypeHandler.class)
})
@Select("SELECT * FROM users WHERE id = #{id}")
User getUserWithResultMap(int id);

3.2 @ResultMap复用映射

@ResultMap("userResultMap")
@Select("SELECT * FROM users")
List<User> getAllUsers();

3.3 嵌套结果映射

@Results({@Result(property = "id", column = "id"),@Result(property = "orders", column = "id",many = @Many(select = "com.example.mapper.OrderMapper.findByUserId"))
})
@Select("SELECT * FROM users WHERE id = #{id}")
User getUserWithOrders(int id);

四、关系映射注解

4.1 @One:一对一映射

public class Order {private Integer id;private String orderNo;@Result(property = "user", column = "user_id",one = @One(select = "com.example.mapper.UserMapper.getUserById"))private User user;
}@Select("SELECT * FROM orders WHERE id = #{id}")
Order getOrderWithUser(int id);

4.2 @Many:一对多映射

public class User {private Integer id;private String name;@Result(property = "orders", column = "id",many = @Many(select = "com.example.mapper.OrderMapper.findByUserId"))private List<Order> orders;
}@Select("SELECT * FROM orders WHERE user_id = #{userId}")
List<Order> findByUserId(int userId);

4.3 嵌套查询 vs 嵌套结果

特性@One/@Many(嵌套查询)嵌套结果(JOIN查询)
执行方式执行多次SQL执行一次SQL
性能N+1查询问题一次查询获取所有数据
适用场景简单关系/数据量小复杂关系/大数据量
灵活性高(独立查询)低(需设计JOIN)
代码量多(需自定义结果映射)

五、动态SQL注解

5.1 @SelectProvider

public class UserSqlProvider {public String findUsers(Map<String, Object> params) {return new SQL() {{SELECT("*");FROM("users");if (params.get("name") != null) {WHERE("name LIKE #{name}");}if (params.get("minAge") != null) {WHERE("age >= #{minAge}");}if (params.get("maxAge") != null) {WHERE("age <= #{maxAge}");}ORDER_BY("id DESC");}}.toString();}
}@SelectProvider(type = UserSqlProvider.class, method = "findUsers")
List<User> findUsers(Map<String, Object> params);

5.2 @InsertProvider

public class UserSqlProvider {public String insertUser(User user) {return new SQL() {{INSERT_INTO("users");if (user.getName() != null) {VALUES("name", "#{name}");}if (user.getEmail() != null) {VALUES("email", "#{email}");}if (user.getAge() > 0) {VALUES("age", "#{age}");}}}.toString();}
}@InsertProvider(type = UserSqlProvider.class, method = "insertUser")
int insertUserDynamic(User user);

5.3 动态SQL构建技巧

// 条件过滤
public String findActiveUsers(Map<String, Object> params) {SQL sql = new SQL().SELECT("*").FROM("users");if (params.containsKey("active")) {boolean active = (Boolean) params.get("active");if (active) {sql.WHERE("status = 1");} else {sql.WHERE("status = 0");}}if (params.containsKey("role")) {String role = (String) params.get("role");sql.WHERE("role = #{role}");}return sql.toString();
}

六、参数处理注解

6.1 @Param:多参数命名

@Select("SELECT * FROM users WHERE name = #{name} AND age = #{age}")
User findByNameAndAge(@Param("name") String name, @Param("age") int age
);

6.2 集合参数处理

@Select({"<script>","SELECT * FROM users WHERE id IN","  <foreach item='id' collection='ids' open='(' separator=',' close=')'>","    #{id}","  </foreach>","</script>"
})
List<User> findByIds(@Param("ids") List<Integer> ids);

6.3 Map参数处理

@SelectProvider(type = UserSqlProvider.class, method = "findByMap")
List<User> findByMap(Map<String, Object> params);

七、高级特性注解

7.1 @Options:执行选项配置

@Insert("INSERT INTO logs(content) VALUES(#{content})")
@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
int insertLog(Log log);// 超时设置
@Select("SELECT * FROM large_table")
@Options(timeout = 30) // 30秒超时
List<Record> getLargeData();// 缓存配置
@Select("SELECT * FROM configs")
@Options(useCache = false, flushCache = Options.FlushCachePolicy.TRUE)
List<Config> getConfigsNoCache();

7.2 @SelectKey:非自增主键获取

@Insert("INSERT INTO orders(order_no) VALUES(#{orderNo})")
@SelectKey(statement = "SELECT LAST_INSERT_ID()", keyProperty = "id", resultType = int.class, before = false)
int insertOrder(Order order);

7.3 @Flush:强制刷新语句

@Flush
List<BatchResult> flush();

八、注解与XML混合使用

8.1 XML中引用注解映射

<!-- UserMapper.xml -->
<resultMap id="userMap" type="User"><id property="id" column="id"/><result property="name" column="name"/><!-- 引用注解定义的映射 --><association property="department" select="com.example.mapper.DepartmentMapper.getById"column="dept_id"/>
</resultMap>

8.2 注解中引用XML映射

@ResultMap("com.example.mapper.UserMapper.userMap")
@Select("SELECT * FROM users WHERE id = #{id}")
User getUserById(int id);

8.3 混合使用最佳实践

  1. 基础CRUD:使用注解
  2. 复杂动态SQL:使用XML
  3. 结果映射:优先使用注解
  4. 关联查询:简单关系用注解,复杂关系用XML
  5. SQL重用:公共SQL片段使用XML定义

九、Spring Boot集成实践

9.1 配置MyBatis注解扫描

@Configuration
@MapperScan("com.example.mapper")
public class MyBatisConfig {@Beanpublic SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();sessionFactory.setDataSource(dataSource);// 配置其他属性return sessionFactory.getObject();}
}

9.2 事务管理配置

@Configuration
@EnableTransactionManagement
public class TransactionConfig {@Beanpublic PlatformTransactionManager transactionManager(DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}
}// 使用事务
@Service
public class UserService {@Transactionalpublic void createUserWithProfile(User user, Profile profile) {userMapper.insert(user);profileMapper.insert(profile);}
}

9.3 分页集成(PageHelper)

@Select("SELECT * FROM users")
Page<User> getUsersByPage();// 控制器中使用
@GetMapping("/users")
public PageInfo<User> getUsers(@RequestParam(defaultValue = "1") int page,@RequestParam(defaultValue = "10") int size) {PageHelper.startPage(page, size);List<User> users = userMapper.getUsersByPage();return new PageInfo<>(users);
}

十、性能优化与最佳实践

10.1 注解开发性能陷阱

  1. N+1查询问题

    // 当获取多个用户时,每个用户都会触发订单查询
    @Select("SELECT * FROM users")
    @Results({@Result(property = "orders", column = "id",many = @Many(select = "findOrdersByUserId"))
    List<User> getAllUsersWithOrders();
    

    解决方案

    • 使用JOIN查询代替嵌套查询
    • 开启二级缓存
    • 使用@ResultMap结合XML配置
  2. 大结果集内存溢出

    // 查询百万级数据
    @Select("SELECT * FROM huge_table")
    List<HugeRecord> getAllHugeRecords();
    

    解决方案

    • 使用分页查询
    • 使用游标查询
    @Select("SELECT * FROM huge_table")
    @Options(resultSetType = ResultSetType.FORWARD_ONLY, fetchSize = 1000)
    void streamHugeRecords(ResultHandler<HugeRecord> handler);
    

10.2 缓存优化策略

// 开启二级缓存
@CacheNamespace(implementation = MybatisRedisCache.class, eviction = LruCache.class,size = 1024)
public interface UserMapper {// ...
}// 缓存配置示例
public class MybatisRedisCache implements Cache {// 实现Redis缓存逻辑
}// 方法级缓存控制
@Select("SELECT * FROM users WHERE id = #{id}")
@Options(useCache = true, flushCache = Options.FlushCachePolicy.FALSE)
User getUserById(int id);

10.3 最佳实践总结

  1. 项目结构规划

    src/main/java
    └── com.example├── config├── controller├── service├── mapper│   ├── UserMapper.java│   ├── OrderMapper.java│   └── sqlprovider│       └── UserSqlProvider.java└── model
    
  2. 注解使用原则

    • 简单SQL使用@Select/@Insert等直接注解
    • 动态SQL使用@*Provider
    • 复杂关联查询使用XML
    • 公共结果映射使用@ResultMap
  3. 性能优化点

    • 避免N+1查询
    • 批量操作使用foreach
    • 大数据集使用流式处理
    • 合理配置缓存
  4. 团队协作规范

    • 统一SQL风格(关键字大写)
    • 参数使用@Param明确命名
    • 复杂SQL添加注释
    • 提供SQL Provider的单元测试

十一、MyBatis注解进阶技巧

11.1 自定义类型处理器

// 枚举类型处理器
@MappedTypes(UserStatus.class)
@MappedJdbcTypes(JdbcType.INTEGER)
public class UserStatusTypeHandler extends BaseTypeHandler<UserStatus> {@Overridepublic void setNonNullParameter(PreparedStatement ps, int i, UserStatus parameter, JdbcType jdbcType) {ps.setInt(i, parameter.getCode());}@Overridepublic UserStatus getNullableResult(ResultSet rs, String columnName) {int code = rs.getInt(columnName);return UserStatus.fromCode(code);}
}// 在Mapper中使用
@Results({@Result(property = "status", column = "status", typeHandler = UserStatusTypeHandler.class)
})
@Select("SELECT * FROM users")
List<User> getAllUsers();

11.2 插件开发(拦截器)

@Intercepts({@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
public class QueryMetricsInterceptor implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {long start = System.currentTimeMillis();Object result = invocation.proceed();long end = System.currentTimeMillis();MappedStatement ms = (MappedStatement) invocation.getArgs()[0];String method = ms.getId();System.out.println(method + " executed in " + (end - start) + "ms");return result;}
}// 注册拦截器
@Configuration
public class MyBatisConfig {@Beanpublic QueryMetricsInterceptor queryMetricsInterceptor() {return new QueryMetricsInterceptor();}
}

11.3 多数据源支持

// 主数据源配置
@Configuration
@MapperScan(basePackages = "com.example.mapper.primary", sqlSessionFactoryRef = "primarySqlSessionFactory")
public class PrimaryDataSourceConfig {@Bean@ConfigurationProperties("spring.datasource.primary")public DataSource primaryDataSource() {return DataSourceBuilder.create().build();}@Beanpublic SqlSessionFactory primarySqlSessionFactory(@Qualifier("primaryDataSource") DataSource dataSource) throws Exception {SqlSessionFactoryBean bean = new SqlSessionFactoryBean();bean.setDataSource(dataSource);return bean.getObject();}
}// 从数据源配置
@Configuration
@MapperScan(basePackages = "com.example.mapper.secondary", sqlSessionFactoryRef = "secondarySqlSessionFactory")
public class SecondaryDataSourceConfig {@Bean@ConfigurationProperties("spring.datasource.secondary")public DataSource secondaryDataSource() {return DataSourceBuilder.create().build();}@Beanpublic SqlSessionFactory secondarySqlSessionFactory(@Qualifier("secondaryDataSource") DataSource dataSource) throws Exception {SqlSessionFactoryBean bean = new SqlSessionFactoryBean();bean.setDataSource(dataSource);return bean.getObject();}
}

十二、总结

12.1 MyBatis注解核心价值

  1. 开发效率提升:减少XML配置,加速开发流程
  2. 代码可读性增强:SQL与Java代码共存
  3. 维护成本降低:修改点集中,无需多文件切换
  4. 类型安全保障:编译时检查SQL参数和结果
  5. 灵活扩展能力:支持自定义TypeHandler、Plugin

12.2 注解适用场景矩阵

项目类型适用度推荐策略
小型项目/微服务★★★★★全注解开发
中型后台系统★★★★☆注解为主,复杂SQL用XML
大型复杂系统★★★☆☆XML为主,简单CRUD用注解
快速原型开发★★★★★全注解开发
遗留系统改造★★☆☆☆逐步引入,混合使用

12.3 未来发展趋势

  1. Kotlin DSL支持:更简洁的SQL构建方式
  2. 响应式集成:与Spring WebFlux深度整合
  3. GraalVM原生支持:提升启动速度和内存效率
  4. AI辅助SQL生成:智能SQL编写建议
  5. 云原生适配:更好支持Serverless架构

掌握MyBatis注解开发,不仅是学习一种技术手段,更是提升开发效率的关键技能。合理运用注解与XML的组合,根据项目需求选择最佳实践,方能在持久层开发中游刃有余。

相关文章:

  • 工作服/反光衣检测算法AI智能分析网关V4安全作业风险预警方案:筑牢矿山/工地/工厂等多场景安全防线
  • 攻防世界-unseping
  • 新版 Xcode 中 CoreData 模型编辑器显示拓扑图功能取消的替代方案
  • Python与数据分析期末复习笔记
  • 数字商城小程序源码,开启便捷电商新体验
  • 高考数学易错考点01 | 临阵磨枪
  • Java高级 | (二十二)Java常用类库
  • C++概率论算法详解:理论基础与实践应用
  • 快速上手pytest
  • 【SAP FICO】在建工程及固定资产
  • [Java 基础]变量,装东西的盒子
  • Linux 下 ChromeDriver 安装
  • Redisson学习专栏(五):源码阅读及Redisson的Netty通信层设计
  • 【分布式技术】KeepAlived高可用架构科普
  • 系统架构设计论文
  • 3.2 HarmonyOS NEXT跨设备任务调度与协同实战:算力分配、音视频协同与智能家居联动
  • P1438 无聊的数列/P1253 扶苏的问题
  • 【自动思考记忆系统】demo (Java版)
  • Day11
  • S1240拨打电话时的工作过程
  • 个人备案的网站可以做什么/客户管理软件crm排名
  • 初中生电脑作业做网站/福州网站排名提升
  • 教育网站 怎么做吸引人/b2b平台是什么意思啊
  • 网站备案更改需要多久/百度怎么注册公司网站
  • 留言网站模板/推广网站大全
  • 模板建站oem代理/软文代写接单平台