您好,登录后才能下订单哦!
# SpringBoot怎样使用MyBatis一对多的关联查询问题
## 一、前言
在现代企业级应用开发中,数据关联查询是非常常见的需求。MyBatis作为Java生态中流行的持久层框架,提供了强大的关联查询支持。本文将详细介绍在SpringBoot项目中如何使用MyBatis实现一对多的关联查询,包括XML配置方式和注解方式两种实现方案。
## 二、环境准备
### 2.1 项目依赖
首先创建一个SpringBoot项目,并添加以下依赖:
```xml
<dependencies>
<!-- SpringBoot Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MyBatis Starter -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<!-- MySQL Connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
假设我们有两个表:department
(部门表)和employee
(员工表),一个部门可以有多个员工。
CREATE TABLE department (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL
);
CREATE TABLE employee (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
department_id INT,
FOREIGN KEY (department_id) REFERENCES department(id)
);
@Data
public class Department {
private Integer id;
private String name;
private List<Employee> employees; // 一对多关联属性
}
@Data
public class Employee {
private Integer id;
private String name;
private Integer departmentId;
}
@Mapper
public interface DepartmentMapper {
Department findByIdWithEmployees(Integer id);
List<Department> findAllWithEmployees();
}
在resources/mapper
目录下创建DepartmentMapper.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.DepartmentMapper">
<!-- 基础结果映射 -->
<resultMap id="departmentResultMap" type="Department">
<id property="id" column="d_id"/>
<result property="name" column="d_name"/>
<!-- 一对多关联映射 -->
<collection property="employees" ofType="Employee">
<id property="id" column="e_id"/>
<result property="name" column="e_name"/>
<result property="departmentId" column="e_department_id"/>
</collection>
</resultMap>
<!-- 根据ID查询部门及员工 -->
<select id="findByIdWithEmployees" resultMap="departmentResultMap">
SELECT
d.id as d_id,
d.name as d_name,
e.id as e_id,
e.name as e_name,
e.department_id as e_department_id
FROM department d
LEFT JOIN employee e ON d.id = e.department_id
WHERE d.id = #{id}
</select>
<!-- 查询所有部门及员工 -->
<select id="findAllWithEmployees" resultMap="departmentResultMap">
SELECT
d.id as d_id,
d.name as d_name,
e.id as e_id,
e.name as e_name,
e.department_id as e_department_id
FROM department d
LEFT JOIN employee e ON d.id = e.department_id
</select>
</mapper>
@Service
public class DepartmentService {
@Autowired
private DepartmentMapper departmentMapper;
public Department getDepartmentWithEmployees(Integer id) {
return departmentMapper.findByIdWithEmployees(id);
}
public List<Department> getAllDepartmentsWithEmployees() {
return departmentMapper.findAllWithEmployees();
}
}
@Mapper
public interface DepartmentAnnotationMapper {
@Select("SELECT id, name FROM department WHERE id = #{id}")
@Results({
@Result(id = true, property = "id", column = "id"),
@Result(property = "name", column = "name"),
@Result(property = "employees", column = "id",
many = @Many(select = "findEmployeesByDepartmentId"))
})
Department findByIdWithEmployeesAnnotation(Integer id);
@Select("SELECT id, name, department_id FROM employee WHERE department_id = #{departmentId}")
List<Employee> findEmployeesByDepartmentId(Integer departmentId);
}
MyBatis提供两种一对多实现方式: 1. 嵌套结果:通过单条SQL关联查询(如XML方式所示) 2. 嵌套查询:通过多条SQL分别查询(如注解方式所示)
嵌套结果效率更高,但SQL较复杂;嵌套查询SQL简单,但可能产生N+1问题。
当使用嵌套查询方式时,如果查询N个部门,每个部门又要查询其员工,就会产生1(查询部门) + N(查询每个部门的员工)次查询。
# application.yml
mybatis:
configuration:
lazy-loading-enabled: true
aggressive-lazy-loading: false
@Select("SELECT id, name FROM department")
@Results({
@Result(id = true, property = "id", column = "id"),
@Result(property = "name", column = "name"),
@Result(property = "employees", column = "id",
many = @Many(select = "findEmployeesByDepartmentId"))
})
List<Department> findAllWithEmployeesPage();
// 在Service中使用
public PageInfo<Department> getDepartmentsWithEmployeesPage(int pageNum, int pageSize) {
PageHelper.startPage(pageNum, pageSize);
List<Department> departments = departmentMapper.findAllWithEmployeesPage();
return new PageInfo<>(departments);
}
@Batch
功能当关联查询的表中存在相同列名时,需要使用别名区分:
<select id="findByIdWithEmployees" resultMap="departmentResultMap">
SELECT
d.id as d_id,
d.name as d_name,
e.id as e_id,
e.name as e_name
FROM department d
LEFT JOIN employee e ON d.id = e.department_id
WHERE d.id = #{id}
</select>
确保collection
标签的ofType
属性正确指定集合元素类型:
<collection property="employees" ofType="Employee">
<!-- 映射配置 -->
</collection>
本文详细介绍了SpringBoot项目中MyBatis一对多关联查询的两种实现方式:XML配置方式和注解方式。XML方式适合复杂查询,可读性强;注解方式简洁,适合简单查询。实际开发中应根据业务需求选择合适的方式,并注意性能优化和N+1问题的解决。
通过合理使用MyBatis的关联查询功能,可以大大简化数据层代码,提高开发效率。希望本文能帮助读者更好地理解和应用MyBatis的一对多查询功能。
完整项目代码可参考GitHub仓库:springboot-mybatis-one-to-many-demo “`
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。