MyBatis关联查询实战:一对一与一对多详细解析
MyBatis是一款强大的持久层框架,提供了多种方式来处理关联查询,其中包括一对一和一对多的情况。在本文中,我们将深入探讨这两种关联查询的实现方式,并通过具体的示例代码进行详细解释。
一对一关联查询
实现一对一关联查询的方式有多种,其中包括嵌套查询(Nested Queries)和结果集嵌套映射(Result Map With Association)。
1. 嵌套查询(Nested Queries)
嵌套查询是通过在 SQL 查询中嵌套另一条查询,将关联的对象查询出来。这通常通过 <select>
元素嵌套在 <resultMap>
中实现。
1.1 数据库表结构
假设有两个表:users
和 addresses
,分别存储用户信息和地址信息。
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 数据库表结构
假设有两个表:users
和 orders
,分别存储用户信息和订单信息。
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种方式都能够实现一对多的关联查询,选择哪种方式取决于个人或项目的偏好。在实际应用中,根据业务需求和性能考虑,选择合适的方式。