Mybatis高级映射多对多查询
紧接着上一篇文章:Mybatis高级映射一对多查询 写
一、开发准备
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
,将用户创建的订单映射到ordersList中;ordersList 3、在Orders中添加订单明细列表属性
List
,将订单的明细映射到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
getOrdersList() { - return ordersList;
- }
- public void setOrdersList(List
ordersList) { - this.ordersList = ordersList;
- }
- //用户创建的订单列表
- private List
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
orderdetails; - public List
getOrderdetails() { - return orderdetails;
- }
- public void setOrderdetails(List
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
findUserAndItemsResultMap() throws Exception; - }
3、OrdersMapperCustom.xml 映射文件
- xml version="1.0" encoding="UTF-8" ?>
- 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 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 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
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的多对多映射就总结完了。