一、MyBatis 注解开发概述
MyBatis 是一个支持自定义 SQL、存储过程和高级映射的持久层框架。除了传统的 XML 方式外,MyBatis 还提供了注解的方式进行 SQL 操作定义。这种注解方式将 SQL 直接写在 Java 接口方法上,简化了开发过程,便于维护和使用。
常见的 MyBatis 注解有:
@Select
:执行查询 SQL。@Insert
:执行插入 SQL。@Update
:执行更新 SQL。@Delete
:执行删除 SQL。@Results
/@Result
:定义结果集的映射。@One
/@Many
:用于处理关联查询(一对一和一对多)。@Param
:为参数命名,方便在 SQL 中使用。@Options
:配置 SQL 执行选项(如返回自增主键)。
二、基于注解的单表增删改查操作
1. 查询操作 (@Select
)
@Select
注解用于执行查询操作,可以直接将查询结果映射为 POJO(Plain Old Java Object)对象或列表。
示例:
public interface UserMapper {
// 查询所有用户
@Select("SELECT * FROM user")
List<User> getAllUsers();
// 根据 ID 查询用户
@Select("SELECT * FROM user WHERE id = #{id}")
User getUserById(int id);
}
在此示例中:
#{id}
是一个占位符,表示方法参数id
,MyBatis 会自动将参数值传入 SQL 中。
2. 插入操作 (@Insert
)
@Insert
用于插入数据,传递的对象属性将自动映射到 SQL 中的字段。
示例:
public interface UserMapper {
// 插入新用户
@Insert("INSERT INTO user(name, age) VALUES(#{name}, #{age})")
int insertUser(User user);
}
3. 更新操作 (@Update
)
@Update
用于更新表中的数据,可以根据特定条件(如 ID)更新记录。
示例:
public interface UserMapper {
// 根据 ID 更新用户信息
@Update("UPDATE user SET name=#{name}, age=#{age} WHERE id=#{id}")
int updateUser(User user);
}
4. 删除操作 (@Delete
)
@Delete
用于删除数据,通常根据 ID 或其他条件来删除记录。
示例:
public interface UserMapper {
// 根据 ID 删除用户
@Delete("DELETE FROM user WHERE id = #{id}")
int deleteUser(int id);
}
三、基于注解的关联查询
1. 一对一关联查询 (@One
)
@One
注解用于处理一对一的关联查询。假设有两张表:user
(用户表)和 user_detail
(用户详情表),它们通过 user.id
与 user_detail.user_id
相关联。
示例:
public interface UserMapper {
// 查询用户及其详情信息
@Select("SELECT * FROM user WHERE id = #{id}")
@Results({
@Result(column = "id", property = "id"),
@Result(column = "name", property = "name"),
@Result(column = "age", property = "age"),
@Result(column = "id", property = "userDetail",
one = @One(select = "com.example.mapper.UserDetailMapper.getUserDetailByUserId"))
})
User getUserWithDetail(int id);
}
public interface UserDetailMapper {
@Select("SELECT * FROM user_detail WHERE user_id = #{userId}")
UserDetail getUserDetailByUserId(int userId);
}
在这个例子中,UserMapper
通过 @One
注解来处理 user_detail
的关联查询,UserDetailMapper
用来查询用户的详情信息。
2. 一对多关联查询 (@Many
)
@Many
注解用于处理一对多的关联查询。假设用户表 user
和订单表 order
之间是一个用户对应多个订单的关系。
示例:
public interface UserMapper {
// 查询用户及其订单信息
@Select("SELECT * FROM user WHERE id = #{id}")
@Results({
@Result(column = "id", property = "id"),
@Result(column = "name", property = "name"),
@Result(column = "age", property = "age"),
@Result(column = "id", property = "orders",
many = @Many(select = "com.example.mapper.OrderMapper.getOrdersByUserId"))
})
User getUserWithOrders(int id);
}
public interface OrderMapper {
@Select("SELECT * FROM `order` WHERE user_id = #{userId}")
List<Order> getOrdersByUserId(int userId);
}
在此示例中,@Many
用于关联查询用户的订单。OrderMapper
中的 getOrdersByUserId
方法根据用户 ID 查询所有订单。
四、多对多关联查询
多对多关系通常需要第三张关联表。例如,student
表与 course
表之间存在多对多关系,学生可以选修多门课程,课程也可以被多个学生选修。中间表 student_course
用来记录学生和课程的对应关系。
数据库结构:
CREATE TABLE student (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50)
);
CREATE TABLE course (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50)
);
CREATE TABLE student_course (
student_id INT,
course_id INT,
FOREIGN KEY (student_id) REFERENCES student(id),
FOREIGN KEY (course_id) REFERENCES course(id)
);
实现多对多查询:
1. StudentMapper:
public interface StudentMapper {
// 查询学生及其所选课程
@Select("SELECT * FROM student WHERE id = #{id}")
@Results({
@Result(column = "id", property = "id"),
@Result(column = "name", property = "name"),
@Result(column = "id", property = "courses",
many = @Many(select = "com.example.mapper.CourseMapper.getCoursesByStudentId"))
})
Student getStudentWithCourses(int id);
}
2. CourseMapper:
public interface CourseMapper {
// 根据学生 ID 查询所选课程
@Select("SELECT course.* FROM course " +
"JOIN student_course ON course.id = student_course.course_id " +
"WHERE student_course.student_id = #{studentId}")
List<Course> getCoursesByStudentId(int studentId);
}
在这个例子中,StudentMapper
和 CourseMapper
协同工作,实现了多对多的查询。通过 student_course
中间表将学生和课程的关系关联起来。
五、其它注解的详细说明
1. @Param
注解
@Param
注解用于为方法中的参数命名,特别是当方法有多个参数时,使用 @Param
可以显式指定参数名,从而避免混淆,提升代码的可读性。
示例:
public interface UserMapper {
// 根据用户名和年龄查询用户
@Select("SELECT * FROM user WHERE name = #{name} AND age = #{age}")
User getUserByNameAndAge(@Param("name") String name, @Param("age") int age);
}
在此示例中,@Param("name")
和 @Param("age")
指定了 SQL 中的参数名称,确保在 SQL 语句中正确映射。
2. @Options
注解
@Options
注解用于配置 SQL 执行时的一些选项。例如,如果表的主键是自增的,可以使用 @Options
来配置插入操作返回生成的主键。
示例:
public interface UserMapper {
// 插入用户并返回自增主键
@Insert("INSERT INTO user(name, age) VALUES(#{name}, #{age})")
@Options(useGeneratedKeys = true, keyProperty = "id")
int insertUser(User user);
}
useGeneratedKeys = true
表示自动生成的主键会被返回并填充到 user
对象的 id
属性中。
六、综合案例
假设我们有一个包含用户、订单、产品的系统。用户可以有多个订单,每个订单包含多个产品(多对多关系)。让我们通过 MyBatis 注解实现该场景。
1. 数据库表结构
CREATE TABLE user (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50)
);
CREATE TABLE product (
id INT PRIMARY KEY AUTO
_INCREMENT,
name VARCHAR(100)
);
CREATE TABLE `order` (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT,
FOREIGN KEY (user_id) REFERENCES user(id)
);
CREATE TABLE order_product (
order_id INT,
product_id INT,
FOREIGN KEY (order_id) REFERENCES `order`(id),
FOREIGN KEY (product_id) REFERENCES product(id)
);
2. 实体类
public class User {
private int id;
private String name;
private List<Order> orders; // 用户的订单
}
public class Order {
private int id;
private int userId;
private List<Product> products; // 订单包含的产品
}
public class Product {
private int id;
private String name;
}
3. Mapper 接口
UserMapper:
public interface UserMapper {
// 查询用户及其订单及产品
@Select("SELECT * FROM user WHERE id = #{id}")
@Results({
@Result(column = "id", property = "id"),
@Result(column = "name", property = "name"),
@Result(column = "id", property = "orders",
many = @Many(select = "com.example.mapper.OrderMapper.getOrdersByUserId"))
})
User getUserWithOrdersAndProducts(int id);
}
OrderMapper:
public interface OrderMapper {
// 根据用户 ID 查询订单
@Select("SELECT * FROM `order` WHERE user_id = #{userId}")
@Results({
@Result(column = "id", property = "id"),
@Result(column = "user_id", property = "userId"),
@Result(column = "id", property = "products",
many = @Many(select = "com.example.mapper.ProductMapper.getProductsByOrderId"))
})
List<Order> getOrdersByUserId(int userId);
}
ProductMapper:
public interface ProductMapper {
// 根据订单 ID 查询产品
@Select("SELECT product.* FROM product " +
"JOIN order_product ON product.id = order_product.product_id " +
"WHERE order_product.order_id = #{orderId}")
List<Product> getProductsByOrderId(int orderId);
}
4. 综合查询操作
调用 getUserWithOrdersAndProducts
方法,可以获取用户、该用户的所有订单以及每个订单包含的产品。
七、总结
通过 MyBatis 注解开发,开发者可以灵活地定义 SQL 操作,简化 XML 配置文件的使用。单表增删改查、一对一、一对多、多对多等关联查询都可以通过注解方式实现,注解方式具有更好的可读性和维护性。此外,合理使用 @Param
和 @Options
注解,能够提高 SQL 操作的灵活性和易用性。