MyBatis关联查询实战:一对一与一对多详细解析

MyBatis关联查询实战:一对一与一对多详细解析

MyBatis是一款强大的持久层框架,提供了多种方式来处理关联查询,其中包括一对一和一对多的情况。在本文中,我们将深入探讨这两种关联查询的实现方式,并通过具体的示例代码进行详细解释。

一对一关联查询

实现一对一关联查询的方式有多种,其中包括嵌套查询(Nested Queries)和结果集嵌套映射(Result Map With Association)。

1. 嵌套查询(Nested Queries)

嵌套查询是通过在 SQL 查询中嵌套另一条查询,将关联的对象查询出来。这通常通过 <select> 元素嵌套在 <resultMap> 中实现。

1.1 数据库表结构

假设有两个表:usersaddresses,分别存储用户信息和地址信息。

sql 复制代码
CREATE TABLE users (
    id INT PRIMARY KEY,
    username VARCHAR(50),
    address_id INT
);

CREATE TABLE addresses (
    id INT PRIMARY KEY,
    city VARCHAR(50),
    country VARCHAR(50)
);

1.2 MyBatis 映射配置

xml 复制代码
<!-- User 实体类 -->
<resultMap id="userMap" type="User">
    <id property="id" column="id" />
    <result property="username" column="username" />
    <association property="address" javaType="Address">
        <id property="id" column="address_id" />
        <result property="city" column="city" />
        <result property="country" column="country" />
    </association>
</resultMap>

<!-- 查询用户信息的 SQL -->
<select id="selectUser" resultMap="userMap">
    SELECT u.id, u.username, a.id as address_id, a.city, a.country
    FROM users u
    JOIN addresses a ON u.address_id = a.id
    WHERE u.id = #{userId}
</select>

1.3 Java 实体类

java 复制代码
public class User {
    private int id;
    private String username;
    private Address address;

    // Getters and setters
}

public class Address {
    private int id;
    private String city;
    private String country;

    // Getters and setters
}

1.4 使用方式

java 复制代码
User user = userMapper.selectUser(1);
System.out.println(user.getUsername());
System.out.println(user.getAddress().getCity());
System.out.println(user.getAddress().getCountry());

2. 结果集嵌套映射(Result Map With Association)

另一种方式是使用 association 元素在 <resultMap> 中创建结果集嵌套映射。

2.1 MyBatis 映射配置

xml 复制代码
<!-- User 实体类 -->
<resultMap id="userMap" type="User">
    <id property="id" column="id" />
    <result property="username" column="username" />
    <association property="address" resultMap="addressMap" />
</resultMap>

<!-- Address 实体类 -->
<resultMap id="addressMap" type="Address">
    <id property="id" column="address_id" />
    <result property="city" column="city" />
    <result property="country" column="country" />
</resultMap>

<!-- 查询用户信息的 SQL -->
<select id="selectUser" resultMap="userMap">
    SELECT u.id, u.username, a.id as address_id, a.city, a.country
    FROM users u
    JOIN addresses a ON u.address_id = a.id
    WHERE u.id = #{userId}
</select>

2.2 使用方式

java 复制代码
User user = userMapper.selectUser(1);
System.out.println(user.getUsername());
System.out.println(user.getAddress().getCity());
System.out.println(user.getAddress().getCountry());

一对多关联查询

实现一对多关联查询的方式也有多种,其中包括嵌套查询(Nested Queries)、嵌套结果集(Nested Result Maps)、集合嵌套映射(Collection Nesting)、以及通过 MyBatis 提供的 collection 元素进行嵌套映射。

1. 嵌套查询(Nested Queries)

嵌套查询是通过在 SQL 查询中嵌套另一条查询,将关联的对象集合查询出来。这通常通过 <select> 元素嵌套在 <resultMap> 中实现。

1.1 数据库表结构

假设有两个表:usersorders,分别存储用户信息和订单信息。

sql 复制代码
CREATE TABLE users (
    id INT PRIMARY KEY,
    username VARCHAR(50)
);

CREATE TABLE orders (
    id INT PRIMARY KEY,
    user_id INT,
    order_name VARCHAR(50)
);

1.2 MyBatis 映射配置

xml 复制代码
<!-- User 实体类 -->
<resultMap id="userMap" type="User">
    <id property="id" column="id" />
    <result property="username" column="username" />
    <collection property="orders" ofType="Order" select="selectOrdersByUserId"/>
</resultMap>

<!-- Order 实体类 -->
<resultMap id="orderMap" type="Order">
    <id property="id" column="id" />
    <result property="orderName" column="order_name" />
</resultMap>

<!-- 查询用户信息的 SQL -->
<select id="selectUser" resultMap="userMap">
    SELECT u.id, u.username
    FROM users u
    WHERE u.id = #{userId}
</select>

<!-- 查询用户订单的 SQL -->
<select id="selectOrdersByUserId" resultMap="orderMap">
    SELECT o.id, o.order_name
    FROM orders o
    WHERE o.user_id = #{userId}
</select>

1.3 Java 实体类

java 复制代码
public class User {
    private int id;
    private String username;
    private List<Order> orders;

    // Getters and setters
}

public class Order {
    private int id;
    private String orderName;

    // Getters and setters
}

1.4 使用方式

java 复制代码
User user = userMapper.selectUser(1);
System.out.println(user.getUsername());

for (Order order : user.getOrders()) {
    System.out.println(order.getOrderName());
}

2. 集合嵌套映射(Collection Nesting)

集合嵌套映射是通过在 <resultMap> 中使用 <collection> 元素进行嵌套映射。

2.1 MyBatis 映射配置

xml 复制代码
<!-- User 实体类 -->
<resultMap id="userMap" type="User">
    <id property="id" column="id" />
    <result property="username" column="username" />
    <collection property="orders" ofType="Order">
        <result property="id" column="id" />
        <result property="orderName" column="order_name" />
    </collection>
</resultMap>

<!-- 查询用户信息的 SQL -->
<select id="selectUser" resultMap="userMap">
    SELECT u.id, u.username, o.id, o.order_name
    FROM users u
    LEFT JOIN orders o ON u.id = o.user_id
    WHERE u.id = #{userId}
</select>

2.2 使用方式

java 复制代码
User user = userMapper.selectUser(1);
System.out.println(user.getUsername());

for (Order order : user.getOrders()) {
    System.out.println(order.getOrderName());
}

3. 使用 collection 元素进行嵌套映射

MyBatis 提供了 collection 元素,可以直接在 <resultMap> 中使用,简化配置。

3.1 MyBatis 映射配置

xml 复制代码
<!-- User 实体类 -->
<resultMap id="userMap" type="User">
    <id property="id" column="id" />
    <result property="username" column="username" />
    <collection property="orders" ofType="Order" column="user_id" select="selectOrdersByUserId"/>
</resultMap>

<!-- Order 实体类 -->
<resultMap id="orderMap" type="Order">
    <id property="id" column="id" />
    <result property="orderName" column="order_name" />
</resultMap>

<!-- 查询用户信息的 SQL -->
<select id="selectUser" resultMap="userMap">
    SELECT u.id, u.username
    FROM users u
    WHERE u.id = #{userId}
</select>

<!-- 查询用户订单的 SQL -->
<select id="selectOrdersByUserId" resultMap="orderMap">
    SELECT o.id, o.order_name
    FROM orders o
    WHERE o.user_id = #{userId}
</select>

3.2 使用方式

java 复制代码
User user = userMapper.selectUser(1);
System.out.println(user.getUsername());

for (Order order : user.getOrders()) {
    System.out.println(order.getOrderName());
}

以上3种方式都能够实现一对多的关联查询,选择哪种方式取决于个人或项目的偏好。在实际应用中,根据业务需求和性能考虑,选择合适的方式。

相关推荐
Loo国昌40 分钟前
【LangChain1.0】第五阶段:RAG高级篇(高级检索与优化)
人工智能·后端·语言模型·架构
计算机学姐1 小时前
基于SpringBoot的演唱会抢票系统
java·spring boot·后端·spring·tomcat·intellij-idea·推荐算法
李慕婉学姐2 小时前
Springboot连锁火锅管理及预测系统sh5s1gn1(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
数据库·spring boot·后端
gjxDaniel3 小时前
Go编程语言入门与常见问题
开发语言·后端·go
sunnyday04265 小时前
Spring Boot 自定义 Starter 实战:从创建到使用的完整指南
spring boot·后端·mybatis
想用offer打牌5 小时前
2025年总结:一个树苗倔强生长
java·后端·开源·go
小北方城市网5 小时前
Redis 分布式锁与缓存三大问题解决方案
spring boot·redis·分布式·后端·缓存·wpf·mybatis
哪里不会点哪里.6 小时前
Spring 核心原理解析:它到底解决了什么问题?
java·后端·spring
小杍随笔6 小时前
【Rust Cargo 目录迁移到 D 盘:不改变安装路径和环境变量的终极方案】
开发语言·后端·rust
沐雨风栉7 小时前
用 Kavita+cpolar 把数字书房装进口袋
服务器·开发语言·数据库·后端·golang