Mybatis高级映射多对多查询

文章封面
摘要: 紧接着上一篇文章:Mybatis高级映射一对多查询 写一、开发准备1、新建数据表(四张表)和添加测试数据DROP TABLE IF EXISTS `i

紧接着上一篇文章:Mybatis高级映射一对多查询

一、开发准备

1、新建数据表(四张表)和添加测试数据

  1. DROP TABLE IF EXISTS `items`;
  2. DROP TABLE IF EXISTS `orders`;
  3. DROP TABLE IF EXISTS `user`;
  4. DROP TABLE IF EXISTS `orderdetail`;
  5. /*items是商品表*/
  6. CREATE TABLE `items` (
  7. `id` INT(11) NOT NULL AUTO_INCREMENT,
  8. `name` VARCHAR(32) NOT NULL COMMENT '商品名称',
  9. `price` FLOAT(10,1) NOT NULL COMMENT '商品定价',
  10. `detail` TEXT COMMENT '商品描述',
  11. `pic` VARCHAR(64) DEFAULT NULL COMMENT '商品图片',
  12. `createtime` DATETIME NOT NULL COMMENT '生产日期',
  13. PRIMARY KEY (`id`)
  14. ) ENGINE=INNODB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
  15. /*user是用户表*/
  16. CREATE TABLE `user` (
  17. `id` INT(11) NOT NULL AUTO_INCREMENT,
  18. `username` VARCHAR(32) NOT NULL COMMENT '用户名称',
  19. `birthday` DATE DEFAULT NULL COMMENT '生日',
  20. `gender` CHAR(1) DEFAULT NULL COMMENT '性别',
  21. `address` VARCHAR(256) DEFAULT NULL COMMENT '地址',
  22. PRIMARY KEY (`id`)
  23. ) ENGINE=INNODB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;
  24. /*orders是订单表*/
  25. CREATE TABLE `orders` (
  26. `id` INT(11) NOT NULL AUTO_INCREMENT,
  27. `user_id` INT(11) NOT NULL COMMENT '下单用户id',
  28. `number` VARCHAR(32) NOT NULL COMMENT '订单号',
  29. `createtime` DATETIME NOT NULL COMMENT '创建订单时间',
  30. `note` VARCHAR(100) DEFAULT NULL COMMENT '备注',
  31. PRIMARY KEY (`id`),
  32. KEY `FK_orders_1` (`user_id`),
  33. CONSTRAINT `FK_orders_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
  34. ) ENGINE=INNODB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
  35. /*orderdetail是订单明细表*/
  36. DROP TABLE IF EXISTS orderdetail;
  37. CREATE TABLE `orderdetail` (
  38. `id` INT(11) NOT NULL AUTO_INCREMENT,
  39. `orders_id` INT(11) NOT NULL COMMENT '订单id',
  40. `items_id` INT(11) NOT NULL COMMENT '商品id',
  41. `items_num` INT(11) DEFAULT NULL COMMENT '商品购买数量',
  42. PRIMARY KEY (`id`),
  43. KEY `FK_orderdetail_1` (`orders_id`),
  44. KEY `FK_orderdetail_2` (`items_id`),
  45. CONSTRAINT `FK_orderdetail_1` FOREIGN KEY (`orders_id`) REFERENCES `orders` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  46. CONSTRAINT `FK_orderdetail_2` FOREIGN KEY (`items_id`) REFERENCES `items` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
  47. ) ENGINE=INNODB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

为了测试,我这里随便填了些数据

20171007155334244.png

20171007155349805.png

20171007155410485.png

20171007155450773.png

2、思路分析

20171007155545742.png

订单项和订单明细是一对多的关系,所以本文主要来查询订单表,然后关联订单明细表,这样就有一对多的问题出来了。

因为多对多比较复杂,总公共有四张表,我们先来分析一下思路:

1、将用户信息映射到User中;

2、在User类中添加订单列表属性ListordersList,将用户创建的订单映射到ordersList中;

3、在Orders中添加订单明细列表属性ListorderDetails,将订单的明细映射到orderDetails中;

4、在OrderDetail中添加Items属性,将订单明细所对应的商品映射到Items中。

经过这样分析后,感觉虽然有点复杂,但是好像不是很难的样子,映射的方法也跟前面的一样,只不过这里表有点多,关系有点复杂。下面来写映射文件:

  1. <select id="findUserAndItemsResultMap" resultMap="UserAndItemsResultMap">
  2. SELECT
  3. orders.*,
  4. user.`username`,
  5. user.`sex`,
  6. user.`address`,
  7. orderdetail.`id` orderdetail_id,
  8. orderdetail.`items_id`,
  9. orderdetail.`items_num`,
  10. orderdetail.`orders_id`,
  11. items.`name` items_name,
  12. items.`detail` items_detail,
  13. items.`price` items_price
  14. FROM
  15. orders,
  16. USER,
  17. orderdetail,
  18. items
  19. WHERE orders.`user_id`=user.`id` AND orders.`id` = orderdetail.`orders_id` AND orderdetail.`items_id`=items.`id`
  20. select>

我们先看一下查询结果:

2017100717420134.png

二、代码实现

1、四个持久化类

① User.java

  1. package com.liuyanzhao.mybatis.po;
  2. import java.util.Date;
  3. import java.util.List;
  4. /**
  5. * 用户的持久类
  6. */
  7. public class User {
  8. private int id; //编号
  9. private String username; //用户名
  10. private String gender; //性别
  11. private Date birthday; //生日
  12. private String address; //地址
  13. public List getOrdersList() {
  14. return ordersList;
  15. }
  16. public void setOrdersList(List ordersList) {
  17. this.ordersList = ordersList;
  18. }
  19. //用户创建的订单列表
  20. private List ordersList;
  21. public int getId() {
  22. return id;
  23. }
  24. public void setId(int id) {
  25. this.id = id;
  26. }
  27. public String getUsername() {
  28. return username;
  29. }
  30. public void setUsername(String username) {
  31. this.username = username;
  32. }
  33. public String getGender() {
  34. return gender;
  35. }
  36. public void setGender(String gender) {
  37. this.gender = gender;
  38. }
  39. public Date getBirthday() {
  40. return birthday;
  41. }
  42. public void setBirthday(Date birthday) {
  43. this.birthday = birthday;
  44. }
  45. public String getAddress() {
  46. return address;
  47. }
  48. public void setAddress(String address) {
  49. this.address = address;
  50. }
  51. }

注意:需要在用户表中加入 订单列表

② Items.java

  1. package com.liuyanzhao.mybatis.po;
  2. import java.util.Date;
  3. /**
  4. * 商品的持久类
  5. */
  6. public class Items {
  7. private int id;
  8. private String name;
  9. private double price;
  10. private String detail;
  11. private String pic;
  12. private Date createTime;
  13. public int getId() {
  14. return id;
  15. }
  16. public void setId(int id) {
  17. this.id = id;
  18. }
  19. public String getName() {
  20. return name;
  21. }
  22. public void setName(String name) {
  23. this.name = name;
  24. }
  25. public double getPrice() {
  26. return price;
  27. }
  28. public void setPrice(double price) {
  29. this.price = price;
  30. }
  31. public String getDetail() {
  32. return detail;
  33. }
  34. public void setDetail(String detail) {
  35. this.detail = detail;
  36. }
  37. public String getPic() {
  38. return pic;
  39. }
  40. public void setPic(String pic) {
  41. this.pic = pic;
  42. }
  43. public Date getCreateTime() {
  44. return createTime;
  45. }
  46. public void setCreateTime(Date createTime) {
  47. this.createTime = createTime;
  48. }
  49. }

③ Orders.java

  1. package com.liuyanzhao.mybatis.po;
  2. import java.util.Date;
  3. import java.util.List;
  4. /**
  5. * 订单的持久类和扩展类
  6. */
  7. public class Orders {
  8. private int id;
  9. private int userId;
  10. private String number;
  11. private Date createTime;
  12. private String note;
  13. //订单明细
  14. private List orderdetails;
  15. public List getOrderdetails() {
  16. return orderdetails;
  17. }
  18. public void setOrderdetails(List orderdetails) {
  19. this.orderdetails = orderdetails;
  20. }
  21. public int getId() {
  22. return id;
  23. }
  24. public void setId(int id) {
  25. this.id = id;
  26. }
  27. public int getUserId() {
  28. return userId;
  29. }
  30. public void setUserId(int userId) {
  31. this.userId = userId;
  32. }
  33. public String getNumber() {
  34. return number;
  35. }
  36. public void setNumber(String number) {
  37. this.number = number;
  38. }
  39. public Date getCreateTime() {
  40. return createTime;
  41. }
  42. public void setCreateTime(Date createTime) {
  43. this.createTime = createTime;
  44. }
  45. public String getNote() {
  46. return note;
  47. }
  48. public void setNote(String note) {
  49. this.note = note;
  50. }
  51. }

注意:订单列表中,需要订单的详细信息,不需要用户信息

④ Orderdetail.java

  1. package com.liuyanzhao.mybatis.po;
  2. /**
  3. * 订单明细的持久类
  4. */
  5. public class Orderdetail {
  6. private int id;
  7. private int ordersId;
  8. private int itemsId;
  9. private int itemsNum;
  10. //明细对应的商品信息
  11. private Items items;
  12. public Items getItems() {
  13. return items;
  14. }
  15. public void setItems(Items items) {
  16. this.items = items;
  17. }
  18. public int getId() {
  19. return id;
  20. }
  21. public void setId(int id) {
  22. this.id = id;
  23. }
  24. public int getOrdersId() {
  25. return ordersId;
  26. }
  27. public void setOrdersId(int ordersId) {
  28. this.ordersId = ordersId;
  29. }
  30. public int getItemsId() {
  31. return itemsId;
  32. }
  33. public void setItemsId(int itemsId) {
  34. this.itemsId = itemsId;
  35. }
  36. public int getItemsNum() {
  37. return itemsNum;
  38. }
  39. public void setItemsNum(int itemsNum) {
  40. this.itemsNum = itemsNum;
  41. }
  42. }

注意:订单明细里,需要 商品信息

2、订单代理 即mapper.java

OrdersMapperCustom.java

  1. package com.liuyanzhao.mybatis.mapper;
  2. import com.liuyanzhao.mybatis.po.User;
  3. import java.util.List;
  4. /**
  5. * 订单 mapper
  6. */
  7. public interface OrdersMapperCustom {
  8. //查询用户购买的商品信息
  9. public List findUserAndItemsResultMap() throws Exception;
  10. }

3、OrdersMapperCustom.xml 映射文件

  1. xml version="1.0" encoding="UTF-8" ?>
  2. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  3. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  4. <mapper namespace="com.liuyanzhao.mybatis.mapper.OrdersMapperCustom">
  5. <resultMap id="UserAndItemsResultMap" type="com.liuyanzhao.mybatis.po.User">
  6. <id column="user_id" property="id">id>
  7. <result column="username" property="username">result>
  8. <result column="gender" property="gender">result>
  9. <result column="address" property="address">result>
  10. <collection property="ordersList" ofType="com.liuyanzhao.mybatis.po.Orders">
  11. <id column="id" property="id">id>
  12. <result column="user_id" property="userId">result>
  13. <result column="number" property="number">result>
  14. <result column="createtime" property="createTime">result>
  15. <result column="node" property="node">result>
  16. <collection property="orderdetails" ofType="com.liuyanzhao.mybatis.po.Orderdetail">
  17. <id column="orderdetail_id" property="id">id>
  18. <result column="items_id" property="itemsId">result>
  19. <result column="items_num" property="itemsNum">result>
  20. <result column="orders_id" property="ordersId">result>
  21. <association property="items" javaType="com.liuyanzhao.mybatis.po.Items">
  22. <id column="items_id" property="id">id>
  23. <result column="items_name" property="name">result>
  24. <result column="items_price" property="price">result>
  25. <result column="items_detail" property="detail">result>
  26. association>
  27. collection>
  28. collection>
  29. resultMap>
  30. <select id="findUserAndItemsResultMap" resultMap="UserAndItemsResultMap">
  31. SELECT
  32. orders.*,
  33. user.username,
  34. user.gender,
  35. user.address,
  36. orderdetail.id orderdetail_id,
  37. orderdetail.items_id,
  38. orderdetail.items_num,
  39. orderdetail.orders_id,
  40. items.name items_name,
  41. items.detail items_detail,
  42. items.price items_price
  43. FROM
  44. orders,
  45. user,
  46. orderdetail,
  47. items
  48. WHERE orders.user_id=user.id AND orders.id = orderdetail.orders_id AND orderdetail.items_id=items.id
  49. select>
  50. mapper>

4、测试类 OrderMapperCustomTest.java

  1. package com.liuyanzhao.mybatis.test;
  2. import com.liuyanzhao.mybatis.mapper.OrdersMapperCustom;
  3. import com.liuyanzhao.mybatis.po.User;
  4. import org.apache.ibatis.io.Resources;
  5. import org.apache.ibatis.session.SqlSession;
  6. import org.apache.ibatis.session.SqlSessionFactory;
  7. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
  8. import org.junit.Before;
  9. import org.junit.Test;
  10. import java.io.InputStream;
  11. import java.util.List;
  12. /**
  13. * Created by Liu_Yanzhao on 2017/8/12.
  14. */
  15. public class OrderMapperCustomTest {
  16. SqlSessionFactory sqlSessionFactory;
  17. @Before
  18. public void setUp() throws Exception {
  19. String resource = "Configuration.xml";
  20. InputStream inputStream = Resources.getResourceAsStream(resource);
  21. sqlSessionFactory = new SqlSessionFactoryBuilder()
  22. .build(inputStream);
  23. }
  24. @Test
  25. public void testFindUserAndItemsResultMap() throws Exception {
  26. SqlSession sqlSession = sqlSessionFactory.openSession();
  27. //创建代理对象
  28. OrdersMapperCustom ordersMapperCustom = sqlSession.getMapper(OrdersMapperCustom.class);
  29. //调用mapper对象
  30. List list = ordersMapperCustom.findUserAndItemsResultMap();
  31. System.out.println(list);
  32. //释放资源
  33. sqlSession.close();
  34. }
  35. }

还有其他文件就不补充了,如 mybatis 全局配置文件

小结

这样多对多的映射就搞定了。不过还有个问题,就是这里多对多的查询会把所有关联的表的信息都查询出来,然后放到pojo中的对应的List或者某个类中,所以即使我只查了个用户信息,但是这个用户里包含了订单,订单项,商品等信息,感觉装的有点多,好像有时候并不需要这么多冗余的数据出来,但是如果用resultType的话查询出来的字段必须对应pojo中的属性,如果有List等,需要手动装入才行。所以下面总结一下对于这种查询数据比较多的时候,resultType和resultMap各有什么作用?

  1. 比如我们只需要将查询用户购买的商品信息明细清单(如用户名、用户地址、购买商品名称、购买商品时间、购买商品数量),那么我们完全不需要其他的信息,这个时候就没必要使用resultMap将所有的信息都搞出来,我们可以自己定义一个pojo,包含我们需要的字段即可,然后查询语句只查询我们需要的字段,这样使用resultType会方便很多。
  2. 如果我们需要查询该用户的所有详细信息,比如用户点击该用户或者鼠标放上去,会出来跟该用户相关的订单啊,订单明细啊,商品啊之类的,然后我们要点进去看下详细情况的时候,那就需要使用resultMap了,必须将所有信息都装到这个User中,然后具体啥信息再从User中取,很好理解。
  3. 总结一点:使用resultMap是针对那些对查询结果映射有特殊要求的功能,,比如特殊要求映射成list中包括多个list。否则使用resultType比较直接。

到这里,mybatis的多对多映射就总结完了。

82 阅读 ← 返回技术栈
图片放大