MyBatis关联查询实战:一对一与一对多详细解析
MyBatis是一款强大的持久层框架,提供了多种方式来处理关联查询,其中包括一对一和一对多的情况。在本文中,我们将深入探讨这两种关联查询的实现方式,并通过具体的示例代码进行详细解释。
一对一关联查询
实现一对一关联查询的方式有多种,其中包括嵌套查询(Nested Queries)和结果集嵌套映射(Result Map With Association)。
1. 嵌套查询(Nested Queries)
嵌套查询是通过在 SQL 查询中嵌套另一条查询,将关联的对象查询出来。这通常通过 <select>
元素嵌套在 <resultMap>
中实现。
1.1 数据库表结构
假设有两个表:users
和 addresses
,分别存储用户信息和地址信息。
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 映射配置
<!-- 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.countryFROM users uJOIN addresses a ON u.address_id = a.idWHERE u.id = #{userId}
</select>
1.3 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 使用方式
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 映射配置
<!-- 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.countryFROM users uJOIN addresses a ON u.address_id = a.idWHERE u.id = #{userId}
</select>
2.2 使用方式
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
,分别存储用户信息和订单信息。
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 映射配置
<!-- 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.usernameFROM users uWHERE u.id = #{userId}
</select><!-- 查询用户订单的 SQL -->
<select id="selectOrdersByUserId" resultMap="orderMap">SELECT o.id, o.order_nameFROM orders oWHERE o.user_id = #{userId}
</select>
1.3 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 使用方式
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 映射配置
<!-- 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_nameFROM users uLEFT JOIN orders o ON u.id = o.user_idWHERE u.id = #{userId}
</select>
2.2 使用方式
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 映射配置
<!-- 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.usernameFROM users uWHERE u.id = #{userId}
</select><!-- 查询用户订单的 SQL -->
<select id="selectOrdersByUserId" resultMap="orderMap">SELECT o.id, o.order_nameFROM orders oWHERE o.user_id = #{userId}
</select>
3.2 使用方式
User user = userMapper.selectUser(1);
System.out.println(user.getUsername());for (Order order : user.getOrders()) {System.out.println(order.getOrderName());
}
以上3种方式都能够实现一对多的关联查询,选择哪种方式取决于个人或项目的偏好。在实际应用中,根据业务需求和性能考虑,选择合适的方式。