1740 字
约 5 分钟
13
注解开发
2026-09-19
无标签
第12章 注解开发
学习使用注解方式进行 SQL 映射和配置
学习进度:48% 代码演示按钮 💻 查看完整代码 - 在线IDE体验
🎯 学习目标
📚
理解核心概念
掌握本章的核心概念和基本原理
🔧
掌握实践技能
学会相关的配置方法和实践技巧
💡
了解应用场景
明确在实际项目中的应用场景和最佳实践
1. 注解开发概述
1.1 注解开发的优势
- 简化配置:减少XML配置文件,提高开发效率
- 类型安全:编译时检查,减少运行时错误
- 代码集中:SQL语句与Java代码在同一位置,便于维护
- IDE支持:更好的代码提示和重构支持
1.2 注解开发的适用场景
- 简单的CRUD操作
- SQL语句相对简单的场景
- 需要快速开发的项目
- 团队更偏向于Java代码而非XML配置
注意:对于复杂的SQL语句和动态SQL,XML配置方式可能更加清晰和易于维护。
2. 基本CRUD注解
2.1 核心注解介绍
| 注解 | 作用 | 示例 |
|---|---|---|
| @Select | 定义查询语句 | @Select("SELECT * FROM users WHERE id = #{id}") |
| @Insert | 定义插入语句 | @Insert("INSERT INTO users(name, email) VALUES(#{name}, #{email})") |
| @Update | 定义更新语句 | @Update("UPDATE users SET name=#{name} WHERE id=#{id}") |
| @Delete | 定义删除语句 | @Delete("DELETE FROM users WHERE id=#{id}") |
| @Options | 配置选项 | @Options(useGeneratedKeys = true, keyProperty = "id") |
2.2 基本CRUD示例
public interface UserMapper {
// 查询单个用户
@Select("SELECT * FROM users WHERE id = #{id}")
User selectUserById(Long id);
// 查询所有用户
@Select("SELECT * FROM users")
List<User> selectAllUsers();
// 插入用户(自动生成主键)
@Insert("INSERT INTO users(username, email, create_time) VALUES(#{username}, #{email}, #{createTime})")
@Options(useGeneratedKeys = true, keyProperty = "id")
int insertUser(User user);
// 更新用户
@Update("UPDATE users SET username=#{username}, email=#{email} WHERE id=#{id}")
int updateUser(User user);
// 删除用户
@Delete("DELETE FROM users WHERE id=#{id}")
int deleteUser(Long id);
}
3. 动态SQL注解
3.1 Provider注解
对于复杂的动态SQL,MyBatis提供了Provider注解:
- @SelectProvider- 动态查询
- @InsertProvider- 动态插入
- @UpdateProvider- 动态更新
- @DeleteProvider- 动态删除
3.2 SQL提供者类
public class UserSqlProvider {
public String selectByCondition(String username, String email) {
return new SQL() {{
SELECT("*");
FROM("users");
if (username != null && !username.trim().isEmpty()) {
WHERE("username LIKE CONCAT('%', #{username}, '%')");
}
if (email != null && !email.trim().isEmpty()) {
WHERE("email LIKE CONCAT('%', #{email}, '%')");
}
}}.toString();
}
public String updateSelective(Long id, String username, String email) {
return new SQL() {{
UPDATE("users");
if (username != null && !username.trim().isEmpty()) {
SET("username = #{username}");
}
if (email != null && !email.trim().isEmpty()) {
SET("email = #{email}");
}
WHERE("id = #{id}");
}}.toString();
}
}
3.3 使用Provider注解
public interface UserMapper {
// 使用动态SQL查询
@SelectProvider(type = UserSqlProvider.class, method = "selectByCondition")
List<User> selectUsersByCondition(@Param("username") String username,
@Param("email") String email);
// 使用动态SQL更新
@UpdateProvider(type = UserSqlProvider.class, method = "updateSelective")
int updateUserSelective(@Param("id") Long id,
@Param("username") String username,
@Param("email") String email);
}
4. 结果映射注解
4.1 @Results和@Result注解
用于定义结果集映射关系:
@Results(id = "userResultMap", value = {
@Result(property = "id", column = "id", id = true),
@Result(property = "username", column = "username"),
@Result(property = "email", column = "email"),
@Result(property = "createTime", column = "create_time")
})
@Select("SELECT id, username, email, create_time FROM users")
List<User> selectUsersWithMapping();
4.2 关联映射注解
一对多关联映射
@Select("SELECT * FROM users")
@Results({
@Result(property = "id", column = "id", id = true),
@Result(property = "username", column = "username"),
@Result(property = "email", column = "email"),
@Result(property = "createTime", column = "create_time"),
@Result(property = "orders", column = "id", javaType = List.class,
many = @Many(select = "com.mybatis.annotation.mapper.OrderMapper.selectOrdersByUserId",
fetchType = FetchType.LAZY))
})
List<User> selectUsersWithOrders();
一对一关联映射
@Select("SELECT * FROM orders")
@Results({
@Result(property = "id", column = "id", id = true),
@Result(property = "orderNo", column = "order_no"),
@Result(property = "user", column = "user_id", javaType = User.class,
one = @One(select = "com.mybatis.annotation.mapper.UserMapper.selectUserById",
fetchType = FetchType.LAZY))
})
List<Order> selectOrdersWithUser();
5. 高级注解特性
5.1 批量操作
// 批量插入
@Insert({
"<script>",
"INSERT INTO users(username, email, create_time) VALUES",
"<foreach collection='users' item='user' separator=','>",
"(#{user.username}, #{user.email}, #{user.createTime})",
"</foreach>",
"</script>"
})
int insertUsers(@Param("users") List<User> users);
5.2 复杂查询条件
// 多条件查询
@Select("SELECT * FROM orders WHERE amount > #{minAmount} AND status = #{status}")
List<Order> selectOrdersByAmountAndStatus(@Param("minAmount") BigDecimal minAmount,
@Param("status") String status);
6. 注解与XML的对比
注解开发
- 优点:
- 配置简单,开发快速
- 类型安全,编译时检查
- 代码集中,便于查看
- 缺点:
- 复杂SQL难以维护
- 动态SQL支持有限
- SQL与Java代码耦合
XML配置
- 优点:
- 支持复杂的动态SQL
- SQL与Java代码分离
- 更好的可读性和维护性
- 缺点:
- 配置文件较多
- 开发效率相对较低
- 运行时才能发现错误
7. 最佳实践
7.1 选择原则
- 简单CRUD:优先使用注解
- 复杂查询:使用XML配置
- 动态SQL:根据复杂度选择Provider或XML
- 团队偏好:保持项目内一致性
7.2 注解开发建议
- 合理使用@Param注解明确参数名称
- 复杂SQL考虑使用Provider类
- 注意SQL注入安全问题
- 适当使用@Results复用结果映射
- 关联查询时注意懒加载配置
7.3 性能优化
- 合理使用延迟加载避免N+1问题
- 批量操作提高数据处理效率
- 适当使用缓存减少数据库访问
- 优化SQL语句和索引
8. 常见问题与解决方案
8.1 参数传递问题
问题:多参数传递时参数名不明确解决:使用@Param注解明确指定参数名称
8.2 结果映射问题
问题:数据库字段名与Java属性名不匹配解决:使用@Result注解或开启驼峰命名转换
8.3 动态SQL复杂度
问题:注解中的动态SQL过于复杂解决:使用Provider类或考虑XML配置
9. 实践练习
练习任务
- 创建用户和订单的注解Mapper接口
- 实现基本的CRUD操作
- 使用Provider实现动态查询
- 配置一对多关联映射
- 实现批量插入功能
- 编写测试用例验证功能
10. 运行示例程序
运行步骤
- 确保MySQL数据库服务正在运行
- 执行src/main/resources/init.sql脚本创建数据库和表
- 修改db.properties中的数据库连接信息
- 运行AnnotationDemo主程序查看注解开发演示
- 运行AnnotationTest测试类验证各项功能
- 观察控制台输出,理解注解开发的执行过程
学习重点:掌握基本CRUD注解的使用方法理解动态SQL的注解实现方式学会配置结果映射和关联查询了解注解与XML配置的适用场景掌握注解开发的最佳实践
返回目录 本章小结
📖 本章小结
本章我们学习了 注解开发 的相关内容,包括:
- 核心概念和基本原理
- 配置方法和实践技巧
- 应用场景和最佳实践
- 常见问题和解决方案
评论
0 条
还没有评论,先写一条吧。