订单和商品多对多关系图
在实际项目开发中,多对多的关联关系非常常见。以订单和商品为例,一个订单可以包含多种商品,而一种商品又可以属于多个订单,订单和商品属于多对多关联关系,订单和商品之间的关联关系如图。
在数据库中,多对多的关联关系通常使用一个中间表来维护,中间表中的订单id作为外键关联订单表的id,中间表中的商品id作为外键关联商品表的id。这三个表之间的关系如图。
下面以订单表与商品表之间的多对多关系为例,讲解如何使用MyBatis处理多对多的关系
- 在名为mybatis的数据库中创建名称为tb_product的商品表和名称为tb_ordersitem 的中间表,同时在表中预先插入几条数据。
CREATE TABLE tb_product (
id INT(32) PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(32), price DOUBLE );
# 插入3条数据
INSERT INTO tb_product VALUES ('1', 'Java基础入门', '44.5');
INSERT INTO tb_product VALUES ('2', 'Java Web 程序开发入门', '38.5');
INSERT INTO tb_product VALUES ('3', 'SSM框架整合实战', '50.0');
# 创建一个名称为tb_ordersitem 的中间表
CREATE TABLE tb_ordersitem (
id INT(32) PRIMARY KEY AUTO_INCREMENT,
orders_id INT(32),
product_id INT(32),
FOREIGN KEY (orders_id) references tb_orders (id),
FOREIGN KEY (product_id) references tb_product (id));
INSERT INTO tb_ordersitem VALUES ('1', '1', '1');
INSERT INTO tb_ordersitem VALUES ('2', '1', '3');
INSERT INTO tb_ordersitem VALUES ('3', '3', '3');
2、创建持久化类Product,并在类中定义商品id、商品名称、商品单价等属性,以及与订单关联的属性。
public class Product {
private Integer id; private String name;
private Double price;
private List<Orders> orders; //关联订单属性
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public List<Orders> getOrders() {
return orders;
}
public void setOrders(List<Orders> orders) {
this.orders = orders;
}
@Override
public String toString() {
return "Product [id=" + id + ", name=" + name
+ ", price=" + price + "]";}
}
3、在商品持久化类中,除了需要添加订单的集合属性外,还需要在订单持久化类(Orders.java)中增加商品集合的属性及其对应的getter/setter方法,Orders类中添加的代码如下。
// 关联商品集合属性
private List<Product> productList;
// 省略getter/setter方法,以及重写的toString()方法
4、创建订单实体映射文件OrdersMapper.xml,用于编写订单信息的查询SQL语句,并在映射文件中编写多对多关联映射查询的配置信息。
<mapper namespace="com.mac.mapper.OrdersMapper">
<select id="findOrdersWithPorduct"parameterType="Integer"
resultMap="OrdersWithProductResult">
select * from tb_orders WHERE id=#{id} </select>
<resultMap type="Orders" id="OrdersWithProductResult">
<id property="id" column="id" /><result property="number" column="number" />
<collection property="productList" column="id" ofType="Product"
select=“com.mac.mapper.ProductMapper.findProductById" ></collection>
</resultMap>
</mapper>
5、创建商品实体映射文件ProductMapper.xml,用于编写订单与商品信息的关联查询SQL语句。
<mapper namespace="com.mac.mapper.ProductMapper">
<select id="findProductById" parameterType="Integer"
resultType="Product">
SELECT * from tb_product where id IN(
SELECT product_id FROM tb_ordersitem
WHERE orders_id = #{id} )
</select>
</mapper>
6、将新创建的映射文件OrdersMapper.xml和ProductMapper.xml的文件路径配置到核心配置文件mybatis-config.xml中。
<mapper resource="com/mac/mapper/OrdersMapper.xml" />
<mapper resource="com/mac/mapper/ProductMapper.xml" />
7、在测试类MyBatisTest中,编写多对多关联查询的测试方法findOrdersTest()。
public void findOrdersTest() {
// 1.生成SqlSession对象
SqlSession session = MyBatisUtils.getSession();
// 2.查询id为1的订单中的商品信息
Orders orders = session.selectOne("com.mac.mapper."
+ "OrdersMapper.findOrdersWithPorduct", 1);
System.out.println(orders);// 3.输出查询结果信息
session.close();// 4.关闭SqlSession
}
8、查询订单及关联商品的另一方式
除了使用嵌套查询的方式查询订单及其关联的商品信息外,还可以在OrdersMapper.xml中使用嵌套结果的方式进行查询。