1. 程式人生 > >Mybatis高階對映多對多查詢

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.   `nameVARCHAR(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;

為了測試,我這裡隨便填了些資料





2、思路分析


訂單項和訂單明細是一對多的關係,所以本文主要來查詢訂單表,然後關聯訂單明細表,這樣就有一對多的問題出來了。

因為多對多比較複雜,總公共有四張表,我們先來分析一下思路:

1、將使用者資訊對映到User中;

2、在User類中新增訂單列表屬性List<Orders>ordersList,將使用者建立的訂單對映到ordersList中;

3、在Orders中新增訂單明細列表屬性List<OrderDetail>orderDetails,將訂單的明細對映到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>

我們先看一下查詢結果:


二、程式碼實現

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<Orders> getOrdersList() {
  14.         return ordersList;
  15.     }
  16.     public void setOrdersList(List<Orders> ordersList) {
  17.         this.ordersList = ordersList;
  18.     }
  19.     //使用者建立的訂單列表
  20.     private List<Orders> 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<Orderdetail> orderdetails;
  15.     public List<Orderdetail> getOrderdetails() {
  16.         return orderdetails;
  17.     }
  18.     public void setOrderdetails(List<Orderdetail> 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<User> findUserAndItemsResultMap() throws Exception;
  10. }

3、OrdersMapperCustom.xml    對映檔案

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3.         PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4.         "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.liuyanzhao.mybatis.mapper.OrdersMapperCustom">
  6.     <!--查詢使用者購買的商品-->
  7.     <resultMap id="UserAndItemsResultMap" type="com.liuyanzhao.mybatis.po.User">
  8.         <!--使用者資訊-->
  9.         <id column="user_id" property="id"></id>
  10.         <result column="username" property="username"></result>
  11.         <result column="gender" property="gender"></result>
  12.         <result column="address" property="address"></result>
  13.         <!--訂單資訊-->
  14.         <!--一個使用者可以對應多個訂單,故使用collection對映-->
  15.         <collection property="ordersList" ofType="com.liuyanzhao.mybatis.po.Orders">
  16.             <id column="id" property="id"></id>
  17.             <result column="user_id" property="userId"></result>
  18.             <result column="number" property="number"></result>
  19.             <result column="createtime" property="createTime"></result>
  20.             <result column="node" property="node"></result>
  21.             <!--訂單明細-->
  22.             <!--一個訂單包括多個明細,故使用collection-->
  23.             <collection property="orderdetails" ofType="com.liuyanzhao.mybatis.po.Orderdetail">
  24.                 <id column="orderdetail_id" property="id"></id>
  25.                 <result column="items_id" property="itemsId"></result>
  26.                 <result column="items_num" property="itemsNum"></result>
  27.                 <result column="orders_id" property="ordersId"></result>
  28.                 <!--商品資訊-->
  29.                 <!--一個訂單明細對應一個商品-->
  30.                 <association property="items" javaType="com.liuyanzhao.mybatis.po.Items">
  31.                     <id column="items_id" property="id"></id>
  32.                     <result column="items_name" property="name"></result>
  33.                     <result column="items_price" property="price"></result>
  34.                     <result column="items_detail" property="detail"></result>
  35.                 </association>
  36.             </collection>
  37.         </collection>
  38.     </resultMap>
  39.     <select id="findUserAndItemsResultMap" resultMap="UserAndItemsResultMap">
  40.         SELECT
  41.         orders.*,
  42.         user.username,
  43.         user.gender,
  44.         user.address,
  45.         orderdetail.id orderdetail_id,
  46.         orderdetail.items_id,
  47.         orderdetail.items_num,
  48.         orderdetail.orders_id,
  49.         items.name items_name,
  50.         items.detail items_detail,
  51.         items.price items_price
  52.         FROM
  53.         orders,
  54.         user,
  55.         orderdetail,
  56.         items
  57.         WHERE orders.user_id=user.id AND orders.id = orderdetail.orders_id AND orderdetail.items_id=items.id
  58.     </select>
  59. </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<User> 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的多對多對映就總結完了。 

參考:傳智播客視訊