springboot怎样使用mybatis一对多的关联查询问题

发布时间:2022-01-27 09:12:44 作者:kk
来源:亿速云 阅读:331
# 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>

2.2 数据库准备

假设我们有两个表: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)
);

三、实体类设计

3.1 基础实体类

@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;
}

四、XML配置方式实现一对多

4.1 Mapper接口定义

@Mapper
public interface DepartmentMapper {
    Department findByIdWithEmployees(Integer id);
    List<Department> findAllWithEmployees();
}

4.2 XML映射文件

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>

4.3 使用示例

@Service
public class DepartmentService {
    @Autowired
    private DepartmentMapper departmentMapper;
    
    public Department getDepartmentWithEmployees(Integer id) {
        return departmentMapper.findByIdWithEmployees(id);
    }
    
    public List<Department> getAllDepartmentsWithEmployees() {
        return departmentMapper.findAllWithEmployees();
    }
}

五、注解方式实现一对多

5.1 使用@Results和@Result注解

@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);
}

5.2 嵌套查询与嵌套结果

MyBatis提供两种一对多实现方式: 1. 嵌套结果:通过单条SQL关联查询(如XML方式所示) 2. 嵌套查询:通过多条SQL分别查询(如注解方式所示)

嵌套结果效率更高,但SQL较复杂;嵌套查询SQL简单,但可能产生N+1问题。

六、解决N+1查询问题

6.1 什么是N+1问题

当使用嵌套查询方式时,如果查询N个部门,每个部门又要查询其员工,就会产生1(查询部门) + N(查询每个部门的员工)次查询。

6.2 解决方案

  1. 使用嵌套结果方式:通过JOIN一次性获取所有数据
  2. 使用@FetchType.LAZY:延迟加载关联数据
  3. 使用MyBatis的懒加载配置
# application.yml
mybatis:
  configuration:
    lazy-loading-enabled: true
    aggressive-lazy-loading: false

七、分页查询处理

7.1 使用PageHelper插件

@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);
}

八、性能优化建议

  1. 合理使用延迟加载:对于不常用的关联数据使用懒加载
  2. 避免过度查询:只查询需要的字段
  3. 使用二级缓存:对于不常变的数据启用缓存
  4. 批量查询优化:对于嵌套查询方式,考虑使用MyBatis的@Batch功能

九、常见问题解决

9.1 列名重复问题

当关联查询的表中存在相同列名时,需要使用别名区分:

<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>

9.2 集合嵌套问题

确保collection标签的ofType属性正确指定集合元素类型:

<collection property="employees" ofType="Employee">
    <!-- 映射配置 -->
</collection>

十、总结

本文详细介绍了SpringBoot项目中MyBatis一对多关联查询的两种实现方式:XML配置方式和注解方式。XML方式适合复杂查询,可读性强;注解方式简洁,适合简单查询。实际开发中应根据业务需求选择合适的方式,并注意性能优化和N+1问题的解决。

通过合理使用MyBatis的关联查询功能,可以大大简化数据层代码,提高开发效率。希望本文能帮助读者更好地理解和应用MyBatis的一对多查询功能。

附录:完整代码示例

完整项目代码可参考GitHub仓库:springboot-mybatis-one-to-many-demo “`

推荐阅读:
  1. mysql一对多关联查询分页错误问题的解决方法
  2. 使用mybatis递归怎么实现一对多

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

springboot mybatis

上一篇:Kotlin委托需要重视的哪些点

下一篇:Linux系统怎么格式化USB设备

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》