MyBatis关联查询详解
在数据库操作中,关联查询是非常常见的需求。MyBatis作为优秀的持久层框架,提供了强大的关联查询功能。本文将通过示例来详解MyBatis中的一对一、一对多和多对多关联查询。
准备工作
首先,我们创建以下数据库表:
-- 订单表
CREATE TABLE tb_order (
id INT AUTO_INCREMENT PRIMARY KEY,
userid INT,
createtime DATETIME,
state VARCHAR(20)
) ENGINE=InnoDB AUTO_INCREMENT=1;
-- 订单详情表
CREATE TABLE tb_orderdetail (
id INT AUTO_INCREMENT PRIMARY KEY,
productId INT,
orderId INT,
num INT,
price DOUBLE(8,2)
) ENGINE=InnoDB AUTO_INCREMENT=1;
-- 商品表
CREATE TABLE tb_product (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100),
price DOUBLE(8,2),
description VARCHAR(500)
) ENGINE=InnoDB AUTO_INCREMENT=1;
-- 用户表
CREATE TABLE tb_user (
ID INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(20),
PASSWORD VARCHAR(50),
sex VARCHAR(2),
birthday DATE,
address VARCHAR(200)
) ENGINE=INNODB AUTO_INCREMENT=1;
表与表之间的关联关系如下:
用户和订单是一对多关系
订单和订单详情是一对多关系
订单详情和商品是一对一关系
一对一查询
需求:查询订单信息以及关联的用户信息。
实体类
public class Order {
private Integer id;
private Date createTime;
private String state;
private User user; // 关联用户信息
// 省略getter和setter方法
}
SQL映射文件
使用resultMap
定义输出参数:
<resultMap type="Order" id="orderMap">
<id column="id" property="id"/>
<result column="createTime" property="createTime"/>
<result column="state" property="state"/>
<association property="user" javaType="User">
<id column="id" property="id"/>
<result column="username" property="name"/>
<result column="sex" property="sex"/>
<result column="password" property="password"/>
<result column="address" property="address"/>
<result column="birthday" property="birthday"/>
</association>
</resultMap>
<select id="findOrders" resultMap="orderMap">
SELECT o.*, u.username, u.address FROM tb_order o, tb_user u WHERE o.userId = u.id
</select>
Mapper接口
public interface OrderMapper {
List<Order> findOrders();
}
测试代码
@Test
public void testFindOrders() {
List<Order> orders = orderMapper.findOrders();
for (Order order : orders) {
System.out.println(order);
}
}
一对多查询
需求:查询用户及其下的所有订单信息。
实体类
在User
类中添加订单的关联属性,该属性是一个集合属性。
public class User {
private Integer id;
private String name;
private String sex;
private String password;
private String address;
private Date birthday;
private List<Order> orders; // 用户下的订单列表
// 省略getter和setter方法
}
SQL映射文件
定义一个包含Order
信息的User
的ResultMap
:
<resultMap type="User" id="userOrderMap">
<id column="id" property="id"/>
<result column="username" property="name"/>
<result column="sex" property="sex"/>
<result column="password" property="password"/>
<result column="address" property="address"/>
<result column="birthday" property="birthday"/>
<collection property="orders" ofType="Order">
<id column="oid" property="id"/>
<result column="createTime" property="createTime"/>
<result column="state" property="state"/>
</collection>
</resultMap>
<select id="findUserOrder" resultMap="userOrderMap">
select u.*, o.id oid, o.createTime, o.state from tb_user u, tb_order o where u.id = o.userId
</select>
Mapper接口
public interface UserMapper {
List<User> findUserOrder();
}
测试代码
@Test
public void testFindUserOrder() {
List<User> users = userMapper.findUserOrder();
for (User user : users) {
System.out.println(user);
for (Order order : user.getOrders()) {
System.out.println("\t" + order);
}
}
}
多对多查询
需求:查询用户及其订单信息和订单详情信息。
SQL语句
查询主表是用户表,关联表通过订单进行关联。
SELECT u.*, o.id oid, o.createTime, o.state, d.id orderDetailId, d.price, d.num
FROM tb_user u, tb_order o, tb_orderdetail d
WHERE u.id = o.userId AND o.id = d.orderId
映射思路
将用户信息映射到
User
中。在
User
类中添加订单列表属性List<Order> orders
,将用户创建的订单映射到orders
。在
Order
中添加订单明细列表属性List<OrderDetail> orderDetails
,将订单的明细映射到orderDetails
。
实体类
public class Order {
private Integer id;
private Date createTime;
private String state;
private User user; // 关联用户信息
private List<OrderDetail> orderDetails; // 订单明细列表
// 省略getter和setter方法
}
public class OrderDetail {
private Integer id;
private Integer productId;
private Integer orderId;
private Integer num;
private Double price;
// 省略getter和setter方法
}
SQL映射文件
定义一个包含Order
信息以及OrderDetail
信息的User
的ResultMap
:
<resultMap type="User" id="userOrderOrderDetailMap">
<id column="id" property="id"/>
<result column="username" property="name"/>
<result column="sex" property="sex"/>
<result column="password" property="password"/>
<result column="address" property="address"/>
<result column="birthday" property="birthday"/>
<collection property="orders" ofType="Order">
<id column="oid" property="id"/>
<result column="createTime" property="createTime"/>
<result column="state" property="state"/>
<collection property="orderDetails" ofType="OrderDetail">
<id column="orderDetailId" property="id"/>
<result column="price" property="price"/>
<result column="num" property="num"/>
</collection>
</collection>
</resultMap>
<select id="findUserOrderOrderDetail" resultMap="userOrderOrderDetailMap">
SELECT u.*, o.id oid, o.createTime, o.state, d.id orderDetailId, d.price, d.num
FROM tb_user u, tb_order o, tb_orderdetail d
WHERE u.id = o.userId AND o.id = d.orderId
</select>
Mapper接口
public interface UserMapper {
List<User> findUserOrderOrderDetail();
}
测试代码
@Test
public void testFindUserOrderOrderDetail() {
List<User> users = userMapper.findUserOrderOrderDetail();
for (User user : users) {
System.out.println(user);
for (Order order : user.getOrders()) {
System.out.println("\t" + order);
for (OrderDetail detail : order.getOrderDetails()) {
System.out.println("\t\t" + detail);
}
}
}
}
通过以上示例,我们可以看到MyBatis在处理关联查询时的强大功能。无论是简单的一对一、一对多,还是复杂的多对多关系,MyBatis都能通过其灵活的映射配置来轻松应对。希望本文能帮助大家更好地理解和应用MyBatis的关联查询。