文章目录
前言
在日常开发中,我们经常需要查询多张表的数据,传统的XML配置方式虽然功能强大,但有时候显得比较繁琐。MyBatis的注解方式为我们提供了一种更简洁、更直观的解决方案 - 注解。
数据库表
sql
-- 用户表
CREATE TABLE user (
id BIGINT PRIMARY KEY,
name VARCHAR(50),
email VARCHAR(100),
dept_id BIGINT
);
-- 部门表
CREATE TABLE department (
id BIGINT PRIMARY KEY,
dept_name VARCHAR(50),
location VARCHAR(100)
);
对应的实体类:
java
@Data
public class User {
private Long id;
private String name;
private String email;
private Long deptId;
private Department department;
}
@Data
public class Department {
private Long id;
private String deptName;
private String location;
}
一对一关联查询
方式一:
最常用的方式是直接在SQL中进行关联查询:
java
@Mapper
public interface UserMapper {
@Select("SELECT *" +
"FROM user u LEFT JOIN department d ON u.dept_id = d.id " +
"WHERE u.id = #{id}")
@Results({
@Result(property = "id", column = "id"),
@Result(property = "name", column = "name"),
@Result(property = "email", column = "email"),
@Result(property = "deptId", column = "dept_id"),
@Result(property = "department.id", column = "dept_id"),
@Result(property = "department.deptName", column = "dept_name"),
@Result(property = "department.location", column = "location")
})
User getUserWithDept(Long id);
}
这种方式简单直接,一次查询就能获取所有需要的数据,性能比较好。
方式二:
如果你更喜欢分步查询的方式,可以使用@One
注解:
java
@Mapper
public interface UserMapper {
@Select("SELECT * FROM user WHERE id = #{id}")
@Results({
@Result(property = "id", column = "id"),
@Result(property = "name", column = "name"),
@Result(property = "email", column = "email"),
@Result(property = "deptId", column = "dept_id"),
@Result(property = "department", column = "dept_id",
one = @One(select = "com.example.mapper.DepartmentMapper.getDeptById"))
})
User getUserWithDept2(Long id);
}
@Mapper
public interface DepartmentMapper {
@Select("SELECT * FROM department WHERE id = #{id}")
Department getDeptById(Long id);
}
这种方式会执行两次SQL查询,先查用户信息,再根据部门ID查询部门信息。虽然查询次数多了,但逻辑更清晰,复用性也更好。
一对多关联查询
假设我们要查询部门及其下属的所有员工:
java
@Data
public class Department {
private Long id;
private String deptName;
private String location;
private List<User> users;
}
使用@Many注解
java
@Mapper
public interface DepartmentMapper {
@Select("SELECT * FROM department WHERE id = #{id}")
@Results({
@Result(property = "id", column = "id"),
@Result(property = "deptName", column = "dept_name"),
@Result(property = "location", column = "location"),
@Result(property = "users", column = "id",
many = @Many(select = "com.example.mapper.UserMapper.getUsersByDeptId"))
})
Department getDeptWithUsers(Long id);
}
@Mapper
public interface UserMapper {
@Select("SELECT * FROM user WHERE dept_id = #{deptId}")
List<User> getUsersByDeptId(Long deptId);
}
多对多关联查询
多对多关系是最复杂的关联关系,通常需要一张中间表来维护关系。我们以用户和角色的关系为例:
sql
-- 角色表
CREATE TABLE role (
id BIGINT PRIMARY KEY,
role_name VARCHAR(50),
description VARCHAR(200)
);
-- 用户角色关联表
CREATE TABLE user_role (
user_id BIGINT,
role_id BIGINT,
PRIMARY KEY (user_id, role_id)
);
对应的实体类:
java
@Data
public class User {
private Long id;
private String name;
private String email;
private Long deptId;
private Department department;
private List<Role> roles;
}
@Data
public class Role {
private Long id;
private String roleName;
private String description;
private List<User> users;
}
方式一:
java
@Mapper
public interface UserMapper {
@Select("SELECT * " +
"FROM user u " +
"LEFT JOIN user_role ur ON u.id = ur.user_id " +
"LEFT JOIN role r ON ur.role_id = r.id " +
"WHERE u.id = #{userId}")
@Results({
@Result(property = "id", column = "id"),
@Result(property = "name", column = "name"),
@Result(property = "email", column = "email"),
@Result(property = "roles", column = "id",
many = @Many(select = "com.example.mapper.RoleMapper.getRolesByUserId"))
})
User getUserWithRoles(Long userId);
}
@Mapper
public interface RoleMapper {
@Select("SELECT r.* FROM role r " +
"INNER JOIN user_role ur ON r.id = ur.role_id " +
"WHERE ur.user_id = #{userId}")
List<Role> getRolesByUserId(Long userId);
}
方式二:
java
@Mapper
public interface RoleMapper {
@Select("SELECT r.id, r.role_name, r.description " +
"FROM role r WHERE r.id = #{roleId}")
@Results({
@Result(property = "id", column = "id"),
@Result(property = "roleName", column = "role_name"),
@Result(property = "description", column = "description"),
@Result(property = "users", column = "id",
many = @Many(select = "com.example.mapper.UserMapper.getUsersWithDeptByRoleId"))
})
Role getRoleWithUsersAndDept(Long roleId);
}
@Mapper
public interface UserMapper {
@Select("SELECT * "+
"FROM user u " +
"INNER JOIN user_role ur ON u.id = ur.user_id " +
"LEFT JOIN department d ON u.dept_id = d.id " +
"WHERE ur.role_id = #{roleId}")
@Results({
@Result(property = "id", column = "id"),
@Result(property = "name", column = "name"),
@Result(property = "email", column = "email"),
@Result(property = "deptId", column = "dept_id"),
@Result(property = "department.deptName", column = "dept_name"),
@Result(property = "department.location", column = "location")
})
List<User> getUsersWithDeptByRoleId(Long roleId);
}
总结
MyBatis的注解方式为我们提供了灵活的联合查询解决方案。虽然在复杂查询方面可能不如XML配置那样强大,但对于大部分常见场景来说已经足够了。