学习目的:专栏的前两节学习中,学会使用一对多以及多对一查询,本节学习使用多对多查询。
一个订单(Order)可能有多种不同的商品(Product),一种商品可以存在于不同的订单中,而每一个产品的订单项(OrderItem),只能有一种商品的详细购买情况(id、name等)以及所属的订单(Order)。
例如:在淘宝购买东西,在同一家店里,第一次:一次性买了鞋和帽子,第二次:一次性买了鞋和裤子,这里的第一二次就是Order,鞋、帽子、裤子就是Product,每一次买的每一种Product的详细情况就是一个OrderItem(包括买了多少件、一共多少钱等)。
综上:一个订单有多种商品,一种商品可以存在于多个订单,这里就有了一对多对多(OrderItem只是维持Product和Order多对多的一个中间项)。
基于此,开始本节课程的学习。
Part 1
准备数据
新建表
create table order_ (
id int(11) NOT NULL AUTO_INCREMENT,
code varchar(32) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
create table order_item_(
id int(11) NOT NULL AUTO_INCREMENT,
oid int ,
pid int ,
number int ,
PRIMARY KEY(id)
)AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
插入数据
INSERT INTO order_ VALUES (1,'code000A');
INSERT INTO order_ VALUES (2,'code000B');
INSERT INTO order_item_ VALUES (null, 1, 1, 100);
INSERT INTO order_item_ VALUES (null, 1, 2, 100);
INSERT INTO order_item_ VALUES (null, 1, 3, 100);
INSERT INTO order_item_ VALUES (null, 2, 2, 100);
INSERT INTO order_item_ VALUES (null, 2, 3, 100);
INSERT INTO order_item_ VALUES (null, 2, 4, 100);
Part 2
新建实体类:Order和OrderItem。
Order
package cn.vaefun.pojo;
import java.util.List;
public class Order {
private int id;
private String code;
List<OrderItem> orderItems;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public List<OrderItem> getOrderItems() {
return orderItems;
}
public void setOrderItems(List<OrderItem> orderItems) {
this.orderItems = orderItems;
}
}
OrderItem
package cn.vaefun.pojo;
public class OrderItem {
private int id;
private int number;
private Order order;
private Product product;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order;
}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
}
Part 3
配置xml,在pojo包中新建两个配置文件:Order.xml和OrderItem.xml。
Order.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.vaefun.pojo">
<resultMap id="orderBean" type="Order">
<id column="oid" property="id"/>
<result column="code" property="code"/>
<collection property="orderItems" ofType="OrderItem">
<id column="oiid" property="id"/>
<result column="number" property="number"/>
<association property="product" javaType="Product">
<id column="pid" property="id"/>
<result column="pname" property="name"/>
<result column="price" property="price"/>
</association>
</collection>
</resultMap>
<select id="listOrder" resultMap="orderBean">
select o.*,p.*,oi.*, o.id 'oid', p.id 'pid', oi.id 'oiid', p.name 'pname'
from order_ o
left join order_item_ oi on o.id =oi.oid
left join product_ p on p.id = oi.pid
</select>
<select id="getOrder" resultMap="orderBean">
select o.*,p.*,oi.*, o.id 'oid', p.id 'pid', oi.id 'oiid', p.name 'pname'
from order_ o
left join order_item_ oi on o.id =oi.oid
left join product_ p on p.id = oi.pid
where o.id = #{id}
</select>
</mapper>
OrderItem.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.vaefun.pojo">
<insert id="addOrderItem" parameterType="OrderItem">
insert into order_item_
values(null,#{order.id},#{product.id},#{number})
</insert>
<insert id="deleteOrderItem" parameterType="OrderItem">
delete from order_item_
where oid = #{order.id} and pid = #{product.id}
</insert>
</mapper>
此后,在mybatis-config.xm中映射相关配置。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<package name="cn.vaefun.pojo"/>
<!-- 扫描该包下的类
使得在后续配置文件pojo.xml中使用resultType的时候,可以直接使用Category,
而不必写全cn.vaefun.pojo.Category-->
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/vaefun_mybatis?characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="cn/vaefun/pojo/pojo.xml"/>
<mapper resource="cn/vaefun/pojo/Product.xml"/>
<mapper resource="cn/vaefun/pojo/Order.xml"/>
<mapper resource="cn/vaefun/pojo/OrderItem.xml"/>
<!-- 映射pojo.xml -->
</mappers>
</configuration>
Part 4
查询操作
通过Order.xml的listOrder对应的sql语句进行查询,联合order_, order_item_, product_ 三张表进行查询:
<select id="listOrder" resultMap="orderBean">
select o.*,p.*,oi.*, o.id 'oid', p.id 'pid', oi.id 'oiid', p.name 'pname'
from order_ o
left join order_item_ oi on o.id =oi.oid
left join product_ p on p.id = oi.pid
</select>
查询结果 id和code字段放在Order对象里, 然后通过一对多的<collection>标签把oiid和number放在OrderItem对象里,最后把pid,pname,price放进Product对象里。
<resultMap id="orderBean" type="Order">
<id column="oid" property="id"/>
<result column="code" property="code"/>
<collection property="orderItems" ofType="OrderItem">
<id column="oiid" property="id"/>
<result column="number" property="number"/>
<association property="product" javaType="Product">
<id column="pid" property="id"/>
<result column="pname" property="name"/>
<result column="price" property="price"/>
</association>
</collection>
</resultMap>
测试代码块:
/**
* 多对多查询
* @param session
*/
public static void listOrder(SqlSession session){
List<Order> orders = session.selectList("listOrder");
for (Order order : orders) {
System.out.println(order.getCode());
List<OrderItem> orderItems = order.getOrderItems();
for (OrderItem orderItem : orderItems) {
System.out.format("\t%s\t%f\t%d%n",orderItem.getProduct().getName(),
orderItem.getProduct().getPrice(),orderItem.getNumber());
}
}
}
测试结果:
listOrder测试结果
Part 5
建立关系:让订单000A和产品z建立了关系。
首先通过id分别获取Order对象和Product对象,然后创建一个新的OrderItem对象,接着设置Order,设置Product,设置数量,最后调用"addOrderItem" 对应的sql语句插入数据。
测试代码:
/**
* 添加一个OrderItem
* @param session
*/
public static void addOrederItem(SqlSession session){
Order order = session.selectOne("getOrder",1);
Product product = session.selectOne("getProduct",6);
OrderItem orderItem = new OrderItem();
orderItem.setProduct(product);
orderItem.setOrder(order);
orderItem.setNumber(109);
session.insert("addOrderItem",orderItem);
}
测试结果:
addOrederItem测试结果
Part 6
删除了订单00A和产品z的关系,再次查询,就看不到产品z了。
删除关系的时候,通过订单id(1)和产品id(6)进行删除。
其实所谓的删除关系,就是删除掉OrderItem记录。
测试代码:
/**
* 删除OrderItem
* @param session
*/
public static void deleteOrderItem(SqlSession session){
Order order = session.selectOne("getOrder",1);
Product product = session.selectOne("getProduct",6);
OrderItem orderItem = new OrderItem();
orderItem.setOrder(order);
orderItem.setProduct(product);
session.delete("deleteOrderItem",orderItem);
}
测试结果: