一、开发准备
1、新建数据表(四张表)和添加测试数据
DROP TABLE IF EXISTS `items`;
DROP TABLE IF EXISTS `orders`;
DROP TABLE IF EXISTS `user`;
DROP TABLE IF EXISTS `orderdetail`;
/*items是商品表*/
CREATE TABLE `items` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(32) NOT NULL COMMENT '商品名称',
`price` FLOAT(10,1) NOT NULL COMMENT '商品定价',
`detail` TEXT COMMENT '商品描述',
`pic` VARCHAR(64) DEFAULT NULL COMMENT '商品图片',
`createtime` DATETIME NOT NULL COMMENT '生产日期',
PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
/*user是用户表*/
CREATE TABLE `user` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`username` VARCHAR(32) NOT NULL COMMENT '用户名称',
`birthday` DATE DEFAULT NULL COMMENT '生日',
`gender` CHAR(1) DEFAULT NULL COMMENT '性别',
`address` VARCHAR(256) DEFAULT NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;
/*orders是订单表*/
CREATE TABLE `orders` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`user_id` INT(11) NOT NULL COMMENT '下单用户id',
`number` VARCHAR(32) NOT NULL COMMENT '订单号',
`createtime` DATETIME NOT NULL COMMENT '创建订单时间',
`note` VARCHAR(100) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`id`),
KEY `FK_orders_1` (`user_id`),
CONSTRAINT `FK_orders_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=INNODB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
/*orderdetail是订单明细表*/
DROP TABLE IF EXISTS orderdetail;
CREATE TABLE `orderdetail` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`orders_id` INT(11) NOT NULL COMMENT '订单id',
`items_id` INT(11) NOT NULL COMMENT '商品id',
`items_num` INT(11) DEFAULT NULL COMMENT '商品购买数量',
PRIMARY KEY (`id`),
KEY `FK_orderdetail_1` (`orders_id`),
KEY `FK_orderdetail_2` (`items_id`),
CONSTRAINT `FK_orderdetail_1` FOREIGN KEY (`orders_id`) REFERENCES `orders` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `FK_orderdetail_2` FOREIGN KEY (`items_id`) REFERENCES `items` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=INNODB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
为了测试,我这里随便填了些数据
2、思路分析
订单项和订单明细是一对多的关系,所以本文主要来查询订单表,然后关联订单明细表,这样就有一对多的问题出来了。
因为多对多比较复杂,总公共有四张表,我们先来分析一下思路:
1、将用户信息映射到User中;
2、在User类中添加订单列表属性
List<Orders>ordersList
,将用户创建的订单映射到ordersList中;3、在Orders中添加订单明细列表属性
List<OrderDetail>orderDetails
,将订单的明细映射到orderDetails中;4、在OrderDetail中添加Items属性,将订单明细所对应的商品映射到Items中。
经过这样分析后,感觉虽然有点复杂,但是好像不是很难的样子,映射的方法也跟前面的一样,只不过这里表有点多,关系有点复杂。下面来写映射文件:
<select id="findUserAndItemsResultMap" resultMap="UserAndItemsResultMap">
SELECT
orders.*,
user.`username`,
user.`sex`,
user.`address`,
orderdetail.`id` orderdetail_id,
orderdetail.`items_id`,
orderdetail.`items_num`,
orderdetail.`orders_id`,
items.`name` items_name,
items.`detail` items_detail,
items.`price` items_price
FROM
orders,
USER,
orderdetail,
items
WHERE orders.`user_id`=user.`id` AND orders.`id` = orderdetail.`orders_id` AND orderdetail.`items_id`=items.`id`
</select>
我们先看一下查询结果:
二、代码实现
1、四个持久化类
① User.java
package com.liuyanzhao.mybatis.po;
import java.util.Date;
import java.util.List;
/**
* 用户的持久类
*/
public class User {
private int id; //编号
private String username; //用户名
private String gender; //性别
private Date birthday; //生日
private String address; //地址
public List<Orders> getOrdersList() {
return ordersList;
}
public void setOrdersList(List<Orders> ordersList) {
this.ordersList = ordersList;
}
//用户创建的订单列表
private List<Orders> ordersList;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
注意:需要在用户表中加入 订单列表
② Items.java
package com.liuyanzhao.mybatis.po;
import java.util.Date;
/**
* 商品的持久类
*/
public class Items {
private int id;
private String name;
private double price;
private String detail;
private String pic;
private Date createTime;
public int getId() {
return id;
}
public void setId(int 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 String getDetail() {
return detail;
}
public void setDetail(String detail) {
this.detail = detail;
}
public String getPic() {
return pic;
}
public void setPic(String pic) {
this.pic = pic;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
}
③ Orders.java
package com.liuyanzhao.mybatis.po;
import java.util.Date;
import java.util.List;
/**
* 订单的持久类和扩展类
*/
public class Orders {
private int id;
private int userId;
private String number;
private Date createTime;
private String note;
//订单明细
private List<Orderdetail> orderdetails;
public List<Orderdetail> getOrderdetails() {
return orderdetails;
}
public void setOrderdetails(List<Orderdetail> orderdetails) {
this.orderdetails = orderdetails;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
}
注意:订单列表中,需要订单的详细信息,不需要用户信息
④ Orderdetail.java
package com.liuyanzhao.mybatis.po;
/**
* 订单明细的持久类
*/
public class Orderdetail {
private int id;
private int ordersId;
private int itemsId;
private int itemsNum;
//明细对应的商品信息
private Items items;
public Items getItems() {
return items;
}
public void setItems(Items items) {
this.items = items;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getOrdersId() {
return ordersId;
}
public void setOrdersId(int ordersId) {
this.ordersId = ordersId;
}
public int getItemsId() {
return itemsId;
}
public void setItemsId(int itemsId) {
this.itemsId = itemsId;
}
public int getItemsNum() {
return itemsNum;
}
public void setItemsNum(int itemsNum) {
this.itemsNum = itemsNum;
}
}
注意:订单明细里,需要 商品信息
2、订单代理 即mapper.java
OrdersMapperCustom.java
package com.liuyanzhao.mybatis.mapper;
import com.liuyanzhao.mybatis.po.User;
import java.util.List;
/**
* 订单 mapper
*/
public interface OrdersMapperCustom {
//查询用户购买的商品信息
public List<User> findUserAndItemsResultMap() throws Exception;
}
3、OrdersMapperCustom.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="com.liuyanzhao.mybatis.mapper.OrdersMapperCustom">
<!--查询用户购买的商品-->
<resultMap id="UserAndItemsResultMap" type="com.liuyanzhao.mybatis.po.User">
<!--用户信息-->
<id column="user_id" property="id"></id>
<result column="username" property="username"></result>
<result column="gender" property="gender"></result>
<result column="address" property="address"></result>
<!--订单信息-->
<!--一个用户可以对应多个订单,故使用collection映射-->
<collection property="ordersList" ofType="com.liuyanzhao.mybatis.po.Orders">
<id column="id" property="id"></id>
<result column="user_id" property="userId"></result>
<result column="number" property="number"></result>
<result column="createtime" property="createTime"></result>
<result column="node" property="node"></result>
<!--订单明细-->
<!--一个订单包括多个明细,故使用collection-->
<collection property="orderdetails" ofType="com.liuyanzhao.mybatis.po.Orderdetail">
<id column="orderdetail_id" property="id"></id>
<result column="items_id" property="itemsId"></result>
<result column="items_num" property="itemsNum"></result>
<result column="orders_id" property="ordersId"></result>
<!--商品信息-->
<!--一个订单明细对应一个商品-->
<association property="items" javaType="com.liuyanzhao.mybatis.po.Items">
<id column="items_id" property="id"></id>
<result column="items_name" property="name"></result>
<result column="items_price" property="price"></result>
<result column="items_detail" property="detail"></result>
</association>
</collection>
</collection>
</resultMap>
<select id="findUserAndItemsResultMap" resultMap="UserAndItemsResultMap">
SELECT
orders.*,
user.username,
user.gender,
user.address,
orderdetail.id orderdetail_id,
orderdetail.items_id,
orderdetail.items_num,
orderdetail.orders_id,
items.name items_name,
items.detail items_detail,
items.price items_price
FROM
orders,
user,
orderdetail,
items
WHERE orders.user_id=user.id AND orders.id = orderdetail.orders_id AND orderdetail.items_id=items.id
</select>
</mapper>
4、测试类 OrderMapperCustomTest.java
package com.liuyanzhao.mybatis.test;
import com.liuyanzhao.mybatis.mapper.OrdersMapperCustom;
import com.liuyanzhao.mybatis.po.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
import java.util.List;
/**
* Created by Liu_Yanzhao on 2017/8/12.
*/
public class OrderMapperCustomTest {
SqlSessionFactory sqlSessionFactory;
@Before
public void setUp() throws Exception {
String resource = "Configuration.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(inputStream);
}
@Test
public void testFindUserAndItemsResultMap() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建代理对象
OrdersMapperCustom ordersMapperCustom = sqlSession.getMapper(OrdersMapperCustom.class);
//调用mapper对象
List<User> list = ordersMapperCustom.findUserAndItemsResultMap();
System.out.println(list);
//释放资源
sqlSession.close();
}
}
还有其他文件就不补充了,如 mybatis 全局配置文件
小结
这样多对多的映射就搞定了。不过还有个问题,就是这里多对多的查询会把所有关联的表的信息都查询出来,然后放到pojo中的对应的List或者某个类中,所以即使我只查了个用户信息,但是这个用户里包含了订单,订单项,商品等信息,感觉装的有点多,好像有时候并不需要这么多冗余的数据出来,但是如果用resultType的话查询出来的字段必须对应pojo中的属性,如果有List等,需要手动装入才行。所以下面总结一下对于这种查询数据比较多的时候,resultType和resultMap各有什么作用?
- 比如我们只需要将查询用户购买的商品信息明细清单(如用户名、用户地址、购买商品名称、购买商品时间、购买商品数量),那么我们完全不需要其他的信息,这个时候就没必要使用resultMap将所有的信息都搞出来,我们可以自己定义一个pojo,包含我们需要的字段即可,然后查询语句只查询我们需要的字段,这样使用resultType会方便很多。
- 如果我们需要查询该用户的所有详细信息,比如用户点击该用户或者鼠标放上去,会出来跟该用户相关的订单啊,订单明细啊,商品啊之类的,然后我们要点进去看下详细情况的时候,那就需要使用resultMap了,必须将所有信息都装到这个User中,然后具体啥信息再从User中取,很好理解。
- 总结一点:使用resultMap是针对那些对查询结果映射有特殊要求的功能,,比如特殊要求映射成list中包括多个list。否则使用resultType比较直接。
到这里,mybatis的多对多映射就总结完了。
参考:传智播客视频