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
- `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的多對多對映就總結完了。
參考:傳智播客視訊