mybatis入門基礎(六)----高級映射(一對一,一對多,多對多)


mybatis入門基礎(六)----高級映射(一對一,一對多,多對多)

一:訂單商品數據模型

1.數據庫執行腳本

創建數據庫表代碼:

 1 CREATE TABLE items (
2 id INT NOT NULL AUTO_INCREMENT,
3 itemsname VARCHAR(32) NOT NULL COMMENT '商品名稱',
4 price FLOAT(10,1) NOT NULL COMMENT '商品定價',
5 detail TEXT COMMENT '商品描述',
6 pic VARCHAR(64) DEFAULT NULL COMMENT '商品圖片',
7 createtime DATETIME NOT NULL COMMENT '生產日期',
8 PRIMARY KEY (id)
9 ) DEFAULT CHARSET=utf8;

10
11 /*Table structure for table `orderdetail` */
12
13 CREATE TABLE orderdetail (
14 id INT NOT NULL AUTO_INCREMENT,
15 orders_id INT NOT NULL COMMENT '訂單id',
16 items_id INT NOT NULL COMMENT '商品id',
17 items_num INT DEFAULT NULL COMMENT '商品購買數量',
18 PRIMARY KEY (id),
19 KEY `FK_orderdetail_1` (`orders_id`),
20 KEY `FK_orderdetail_2` (`items_id`),
21 CONSTRAINT `FK_orderdetail_1` FOREIGN KEY (`orders_id`) REFERENCES `orders` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
22 CONSTRAINT `FK_orderdetail_2` FOREIGN KEY (`items_id`) REFERENCES `items` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
23 ) DEFAULT CHARSET=utf8;

24
25 /*Table structure for table `orders` */
26
27 CREATE TABLE orders (
28 id INT NOT NULL AUTO_INCREMENT,
29 user_id INT NOT NULL COMMENT '下單用戶id',
30 number VARCHAR(30) NOT NULL COMMENT '訂單號',
31 createtime DATETIME NOT NULL COMMENT '創建訂單時間',
32 note VARCHAR(100) DEFAULT NULL COMMENT '備注',
33 PRIMARY KEY (`id`),
34 KEY `FK_orders_1` (`user_id`),
35 CONSTRAINT `FK_orders_id` FOREIGN KEY (`user_id`) REFERENCES `t_user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
36 ) DEFAULT CHARSET=utf8;

37
38 /*Table structure for table `t_user` */
39
40 CREATE TABLE t_user (
41 id INT NOT NULL AUTO_INCREMENT,
42 username VARCHAR(32) NOT NULL COMMENT '用戶名稱',
43 birthday DATE DEFAULT NULL COMMENT '生日',
44 sex CHAR(1) DEFAULT NULL COMMENT '性別',
45 address VARCHAR(256) DEFAULT NULL COMMENT '地址',
46 PRIMARY KEY (`id`)
47 ) DEFAULT CHARSET=utf8;
View Code

測試數據代碼:

 1 /*Data for the table `items` */
2
3 INSERT INTO items(itemsname,price,detail,pic,createtime) VALUES
4 ('台式機',3000.0,'該電腦質量非常好!',NULL,'2015-07-07 13:28:53'),
5 ('筆記本',6000.0,'筆記本性能好,質量好!',NULL,'2015-07-08 13:22:57'),
6 ('背包',200.0,'名牌背包,容量大質量好!',NULL,'2015-07-010 13:25:02');

7
8 /*Data for the table `orderdetail` */
9
10 INSERT INTO `orderdetail`(`orders_id`,`items_id`,`items_num`) VALUES
11 (1,1,1),
12 (1,2,3),
13 (2,3,4),
14 (3,2,3);

15
16 /*Data for the table `orders` */
17
18 INSERT INTO `orders`(`user_id`,`number`,`createtime`,`note`) VALUES
19 (1,'1000010','2015-06-04 13:22:35',NULL),
20 (1,'1000011','2015-07-08 13:22:41',NULL),
21 (2,'1000012','2015-07-17 14:13:23',NULL),
22 (3,'1000012','2015-07-16 18:13:23',NULL),
23 (4,'1000012','2015-07-15 19:13:23',NULL),
24 (5,'1000012','2015-07-14 17:13:23',NULL),
25 (6,'1000012','2015-07-13 16:13:23',NULL);

26
27 /*Data for the table `user` */
28
29 INSERT INTO `t_user`(`username`,`birthday`,`sex`,`address`) VALUES
30 ('王五',NULL,'2',NULL),
31 ('張三','2014-07-10','1','北京市'),
32 ('張小明',NULL,'1','河南鄭州'),
33 ('陳小明',NULL,'1','河南鄭州'),
34 ('張三豐',NULL,'1','河南鄭州'),
35 ('陳小明',NULL,'1','河南鄭州'),
36 ('王五',NULL,NULL,NULL),
37 ('小A','2015-06-27','2','北京'),
38 ('小B','2015-06-27','2','北京'),
39 ('小C','2015-06-27','1','北京'),
40 ('小D','2015-06-27','2','北京');
View Code

2.數據模型分析思路

(1).每張表記錄的數據內容:分模塊對每張表記錄的內容進行熟悉,相當 於你學習系統 需求(功能)的過程;

(2).每張表重要的字段設置:非空字段、外鍵字段;

(3).數據庫級別表與表之間的關系:外鍵關系;

(4).表與表之間的業務關系: 在分析表與表之間的業務關系時一定要建立在某個業務意義基礎上去分析 。

3.針對訂單商品模型的數據庫思路分析:

用戶表:t_ user--> 記錄了購買商品的用戶信息

訂單表:orders-->記錄了用戶所創建的訂單(購買商品的訂單)

訂單明細表:orderdetail-->記錄了訂單的詳細信息即購買商品的信息

商品表:items-->記錄了商品信息

表與表之間的業務關系:

在分析表與表之間的業務關系時需要建立 在某個業務意義基礎上去分析。

先分析數據級別之間有關系的表之間的業務關系:

t_user 和 orders :

t_user---->orders :一個用戶可以創建多個訂單,一對多

orders--->t_user :一個訂單只由一個用戶創建,一對一

orders和orderdetail :

orders--->orderdetail :一個訂單可以包括多個訂單明細,因為一個訂單可以購買多個商品,每個商品的購買信息在 orderdetail 記錄,一對多關系

orderdetail--> orders:一個訂單明細只能包括在一個訂單中,一對一

orderdetail和 itesm :

orderdetail---> itesms :一個訂單明細只對應一個商品信息,一對一

items--> orderdetail: 一個商品可以包括在多個訂單明細 ,一對多

再分析數據庫級別沒有關系的表之間是否有業務關系:

orders和 items :

orders 和 items 之間可以通過 orderdetail表建立 關系。

4.分析之后畫出對應的圖,方便直觀的了解業務關系

二、一對一查詢

2.1.需求:查詢訂單信息,關聯查詢用戶信息;

2.2.resultType實現

2.2.1.sql語句

確定查詢的主表:訂單表,確定查詢的關聯表:用戶表。

1 SELECT    t1.*,
2 t2.username,
3 t2.sex,
4 t2.address
5 FROM
6 orders t1,
7 t_user t2
8 WHERE t1.user_id=t2.id

2.2.2.創建entity實體

用戶實體:User.java

package com.mybatis.entity;
import java.util.Date;
import java.util.List;
/**
* @ClassName: User
* @Description: TODO(用戶實體)
* @author 阿赫瓦里
*/

public class User {
private Integer id;
// 姓名
private String username;
// 性別
private String sex;
// 地址
private String address;
// 生日
private Date birthday;
// 用戶創建的訂單列表
private List<Orders> ordersList;
// getter and setter ......
}

訂單實體:orders.java

package com.mybatis.entity;
import java.util.Date;
import java.util.List;
/**
* @ClassName: Orders
* @Description: TODO(訂單實體)
* @author 阿赫瓦里
*/

public class Orders {
/** 主鍵訂單Id */
private Integer id;
/** 下單用戶id */
private Integer userid;
/** 訂單號 */
private String number;
/** 創建訂單時間 */
private Date createTime;
/** 備注 */
private String note;
// 用戶信息
private User user;
// 訂單明細
private List<OrderDetail> orderdetails;
// getter and setter ......
}

商品實體:Items.java

package com.mybatis.entity;
import java.util.Date;
/**
* @ClassName: Items
* @Description: TODO(商品實體類)
* @author 阿赫瓦里
*/

public class Items {
/** 商品表主鍵Id */
private Integer id;
/** 商品名稱 */
private String itemsName;
/** 商品定價 */
private float price;
/** 商品描述 */
private String detail;
/** 商品圖片 */
private String picture;
/** 生產日期 */
private Date createTime;
// getter and setter ......
}

訂單明細實體:OrderDetail.java

package com.mybatis.entity;
/**
* @ClassName: OrderDetail
* @Description: TODO(訂單明細實體)
* @author 阿赫瓦里
*/

public class OrderDetail {
/** 主鍵,訂單明細表Id */
private Integer id;
/** 訂單Id */
private Integer ordersId;
/** 商品id */
private Integer itemsId;
/** 商品購買數量 */
private Integer itemsNum;
// 明細對應的商品信息
private Items items;
// getter and setter ......
}

創建一個包裝類,將查詢到的信息可以全部映射到此類:OrdersCustom.java

/**
* @ClassName: OrdersCustom
* @Description: TODO(訂單的擴展類,通過此類映射訂單和用戶的查詢結果,讓此類繼承字段較多的實體類)
* @author: 阿赫瓦里
*/

public class OrdersCustom extends Orders {
// 添加用戶的屬性
private String username;
private String sex;
private String address;
// getter and setter......
}

2.2.3.創建OrdersCustomMapper.java

package com.mybatis.Mapper;
import java.util.List;
import com.mybatis.entity.OrdersCustom;

/**
* @ClassName: OrdersMapperCustom
* @Description: TODO(OrdersMapperCustom的mapper)
* @author 阿赫瓦里
*/

public interface OrdersCustomMapper {
/** 查詢訂單,關聯查詢用戶信息 */
public List<OrdersCustom> findOrdersUser();
}

2.2.4.創建OrdersCustomMapper.xml和上面對應的接口名稱一致,以便通過mapper接口加載配置文件

<?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">

<!-- namespace命名空間,作用就是對sql進行分類化的管理,理解為sql隔離
注意:使用mapper代理開發時,namespace有特殊作用,namespace等於mapper接口地址
-->

<mapper namespace="com.mybatis.mapper.OrdersCustomMapper">
<!-- 查詢訂單,關聯查詢用戶信息 -->
<select id="findOrdersUser" resultType="com.mybatis.entity.OrdersCustom">
SELECT t1.*,
t2.username,
t2.sex,
t2.address
FROM
orders t1,
t_user t2
WHERE t1.user_id=t2.id
</select>
</mapper>

2.3.resultMap實現

2.3.1. sql語句同上

2.3.2. resultMap映射思路:

使用 resultMap 將查詢結果中的訂單信息映射到 Orders 對象中,在 orders 類中添加 User 屬性,將關聯查詢出來的用戶信息映射到 orders 對象中的 user 屬性中(上面orders實體中已經添加)。

2.3.3 ordersCustomMapper.xml

1. 定義resultMap

 1 <!-- 定義查詢訂單關聯用戶的 resultMap,將整個的查詢結果映射到com.mybatis.entity.Orders中 -->
2 <resultMap type="com.mybatis.entity.Orders" id="OrdersUserResultMap">
3 <!-- 配置映射的訂單信息 -->
4
5 <!-- id:查詢列中的唯一標識,訂單信息中的唯一標識,如果多列組成唯一標識(如:一般數據庫設計中的字典表 使用聯合主鍵),就需要配置多個id
6 column:訂單信息的唯一標識 列
7 property:訂單信息的唯一標識列所映射到orders中的那個屬性(假如:數據庫中orders表中的主鍵為orders_id,而實體屬性名稱為ordersId,
8 則這個配置應為<id column="orders_id" property="ordersId"/>,類似hibernate實體映射文件配置)。
9 -->

10 <id column="id" property="id"/>
11 <result column="user_id" property="userid"/>
12 <result column="number" property="number"/>
13 <result column="createtime" property="createTime"/>
14 <result column="note" property="note"/>
15
16 <!-- 配置映射的關聯用戶信息 -->
17
18 <!--association:用於映射關聯查詢單個對象的信息
19 property:要將關聯查詢的用戶信息映射到Orders中那個屬性
20 -->

21 <association property="user" javaType="com.mybatis.entity.User">
22 <!-- id:關聯查詢用戶的唯一標識
23 column:指定唯一標識用戶信息的列
24 property:映射到user的那個屬性
25 -->

26 <id column="user_id" property="id"/>
27 <result column="username" property="username"/>
28 <result column="sex" property="sex"/>
29 <result column="address" property="address"/>
30 </association>
31
32 </resultMap>

2. statement定義

 1     <!-- 查詢訂單,關聯查詢用戶信息,使用resultMap實現 -->
2 <select id="findOrdersUserResultMap" resultMap="OrdersUserResultMap">
3 SELECT t1.*,
4 t2.username,
5 t2.sex,
6 t2.address
7 FROM
8 orders t1,
9 t_user t2
10 WHERE t1.user_id=t2.id
11 </select>

3.OrderCustomMapper.java接口中添加下面的方法

/** 查詢訂單關聯查詢用戶信息,使用reslutMap實現*/
public List<Orders>findOrdersUserResultMap();

4.對是resultType和resultMap實現的Junit測試

 1 package com.mybatis.test;
2
3 import java.io.InputStream;
4 import java.util.List;
5
6 import org.apache.ibatis.io.Resources;
7 import org.apache.ibatis.session.SqlSession;
8 import org.apache.ibatis.session.SqlSessionFactory;
9 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
10 import org.junit.Before;
11 import org.junit.Test;
12
13 import com.mybatis.entity.Orders;
14 import com.mybatis.entity.OrdersCustom;
15 import com.mybatis.mapper.OrdersCustomMapper;
16
17 public class OrdersCustomMapperTest {
18
19 private SqlSessionFactory sqlSessionFactory;
20
21 // 此方法是在執行findUserByIdTest之前執行
22 @Before
23 public void setUp() throws Exception {
24 String resource = "SqlMapConfig.xml";
25 InputStream inputStream = Resources.getResourceAsStream(resource);
26 // 創建SqlSessionFcatory
27 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
28 }
29
30 // 查詢訂單,關聯查詢用戶信息,使用resultType實現的測試
31 @Test
32 public void TestFindOrdersUser() {
33 SqlSession sqlSession = sqlSessionFactory.openSession();
34 // 創建代理對象
35 OrdersCustomMapper oc = sqlSession.getMapper(OrdersCustomMapper.class);
36 // 調用mapper的方法
37 List<OrdersCustom> list = oc.findOrdersUser();
38 System.out.println(list);
39 sqlSession.close();
40 }
41
42 // 查詢訂單,關聯查詢用戶信息,使用resultMap實現的測試
43 @Test
44 public void TestFindOrdersUserResultMap() {
45 SqlSession sqlSession = sqlSessionFactory.openSession();
46 // 創建代理對象
47 OrdersCustomMapper oc = sqlSession.getMapper(OrdersCustomMapper.class);
48 // 調用mapper的方法
49 List<Orders> list = oc.findOrdersUserResultMap();
50 System.out.println(list);
51 sqlSession.close();
52
53 }
54
55 }
View Code

5.resultType 和 resultMap 實現一對一查詢小結

實現一對一查詢:

a.resultType :使用 resultType 實現較為簡單,如果 pojo 中沒有包括查詢出來的列名,需要增加列名對應的屬性,即可完成映射。

b.如果沒有查詢結果的特殊要求建議使用 resultType 。

c.resultMap :需要單獨定義 resultMap ,實現有點麻煩,如果對查詢結果有特殊的要求,使用 resultMap 可以完成將關聯查詢映射 pojo 的屬性中。

d.resultMap 可以實現延遲加載, resultType 無法實現延遲加載。

三、一對多查詢

 3.1. 需求:查詢訂單(關聯用戶)及訂單明細;

 3.2. 在 orders.java 類中添加 List<orderDetail> orderDetails 屬性(上面實體已添加)

最終會將訂單信息映射到 orders 中,訂單所對應的訂單明細映射到 orders 中的orderDetails 屬性中.

3.3.在ordersCustomMapper.xml中添加如下代碼

<!-- 查詢訂單關聯查詢用戶及訂單明細 -->
<select id="findOrdersAndOrderDetailResultMap" resultMap="ordersAndOrderDetailResultMap">
SELECT
t1.*,
t2.username,
t2.sex,
t2.address,
t3.id orderdetail_id,
t3.items_id,
t3.items_num,
t3.orders_id
FROM
orders t1,
t_user t2,
orderdetail t3
WHERE t1.user_id = t2.id AND t3.orders_id=t1.id
</select>

resultMap的定義同樣添加到ordersCustomMapper.xml

<!-- 查詢訂單(關聯用戶)及訂單明細的resultMap -->
<resultMap type="com.mybatis.entity.Orders" id="ordersAndOrderDetailResultMap" extends="OrdersUserResultMap">
<!-- 訂單信息 -->
<!-- 關聯用戶信息 -->
<!-- 使用extends繼承,不用在中配置訂單信息和用戶信息的映射-->
<!-- 關聯訂單明細信息
一個訂單關聯查詢出了多條訂單明細,要使用collection映射
collection:對關聯查詢到的多條記錄映射到集合中
property:將關聯查詢到的多條記錄映射到orders類的那個屬性
ofType:指定映射的集合屬性中pojo的類型
-->

<collection property="orderdetails" ofType="com.mybatis.entity.OrderDetail">
<!-- id:唯一標識
property:要將訂單明細的唯一標識映射到com.mybatis.entity.OrderDetail的那個屬性
-->

<id column="orderdetail_id" property="id"/>
<result column="items_id" property="itemsId"/>
<result column="items_num" property="itemsNum"/>
<result column="orders_id" property="ordersId"/>
</collection>
</resultMap>

3.4. 在OrderCustomMapper.java接口類中添加一個方法

/**查詢訂單(關聯用戶)以及訂單明細*/
public List<OrderDetail>findOrdersAndOrderDetailResultMap();

3.5.在Junit測試類中添加測試方法

// 查詢訂單(關聯用戶)以及訂單明細的測試
@Test
public void TestFindOrdersAndOrderDetailResultMap() {
SqlSession sqlSession = sqlSessionFactory.openSession();
// 創建代理對象
OrdersCustomMapper oc = sqlSession.getMapper(OrdersCustomMapper.class);
// 調用mapper的方法
List<OrderDetail> list = oc.findOrdersAndOrderDetailResultMap();
System.out.println(list);
sqlSession.close();
}

3.6. 小結

mybatis 使用 resultMap 的 collection 對關聯查詢的多條記錄映射到一個 list 集合屬性中。

使用 resultType 實現:將訂單明細映射到orders中的orderdetails中,需要自己處理,使用雙重循環遍歷,去掉重復記錄,將訂單明細放在orderdetails中。

四、多對多查詢

4.1.需求:查詢用戶以及用戶購買的商品信息

4.2.映射思路

將用戶信息映射到 user 中。

在 user 類中添加訂單列表屬性 List<Orders> orderslist ,將用戶創建的訂單映射到orderslist;

在 Orders 中添加訂單明細列表屬性 List<OrderDetail>orderdetials ,將訂單的明細映射到 orderdetials;

在 OrderDetail 中添加 Items 屬性,將訂單明細所對應的商品映射到 Item;

4.3.OrdersCustomMapper.xml添加如下代碼

<!-- 查詢用戶即購買的商品信息的ResultMap -->
<resultMap type="com.mybatis.entity.User" id="userAndItemsResultMap">
<!-- 用戶信息 -->
<id column="user_id" property="id"/>
<result column="username" property="username"/>
<result column="sex" property="sex"/>
<result column="address" property="address"/>
<!-- 訂單信息
一個用戶對應多個訂單,使用collection映射 -->

<collection property="ordersList" ofType="com.mybatis.entity.Orders">
<id column="id" property="id"/>
<result column="user_id" property="userid"/>
<result column="number" property="number"/>
<result column="createtime" property="createTime"/>
<result column="note" property="note"/>
<!-- 訂單明細
一個訂單包括 多個明細
-->

<collection property="orderdetails" ofType="com.mybatis.entity.OrderDetail">
<id column="orderdetail_id" property="id"/>
<result column="items_id" property="itemsId"/>
<result column="items_num" property="itemsNum"/>
<result column="orders_id" property="ordersId"/>
<!-- 商品信息
一個訂單明細對應一個商品
-->

<association property="items" javaType="com.mybatis.entity.Items">
<id column="items_id" property="id"/>
<result column="items_name" property="itemsName"/>
<result column="items_detail" property="detail"/>
<result column="items_price" property="price"/>
</association>
</collection>
</collection>
</resultMap>
<!-- 查詢用戶及用戶購買的商品信息,使用resulaMap-->
<select id="findUserAndItemsResultMap" resultMap="userAndItemsResultMap">
SELECT
t1.*,
t2.username,
t2.sex,
t2.address,
t3.id orderdetail_id,
t3.items_id,
t3.items_num,
t3.orders_id,
t4.itemsname items_name,
t4.detail items_detail,
t4.price items_price
FROM
orders t1,
t_user t2,
orderdetail t3,
items t4
WHERE t1.user_id = t2.id AND t3.orders_id=t1.id AND t3.items_id = t4.id
</select>

4.4. 在OrderCustomMapper.java添加如下方法

/** 查詢用戶及用戶所購買的商品信息 */
public List<User> findUserAndItemsResultMap();

4.5.在Junit測試類中添加測試方法

// 查詢用戶及用戶購買的商品的信息
@Test
public void TestFindUserAndItemsResultMap() {
SqlSession sqlSession = sqlSessionFactory.openSession();
// 創建代理對象
OrdersCustomMapper oc = sqlSession.getMapper(OrdersCustomMapper.class);
// 調用mapper的方法
List<User> list = oc.findUserAndItemsResultMap();
System.out.println(list);
sqlSession.close();
}

4.6.resultMap總結

resultType :

作用:將查詢結果按照sql列名pojo屬性名一致性映射到pojo中。

場合:

常見一些明細記錄的展示,比如用戶購買商品明細,將關聯查詢信息全部展示在頁面時,此時可直接使用 resultType 將每一條記錄映射到 pojo 中,在前端頁面遍歷 list( list 中是 pojo )即可。

resultMap :

使用 association 和 collection 完成一對一和一對多高級映射(對結果有特殊的映射要求)。

association :

作用:將關聯查詢信息映射到一個pojo對象中。

場合:

為了方便查詢關聯信息可以使用 association 將關聯訂單信息映射為用戶對象的 pojo屬性中,比如:查詢訂單及關聯用戶信息。

使用 resultType 無法將查詢結果映射到 pojo 對象的 pojo 屬性中,根據對結果集查詢遍歷的需要選擇使用 resultType 還是 resultMap 。

collection :

作用:將關聯查詢信息映射到一個list集合中。

場合:

為了方便查詢遍歷關聯信息可以使用 collection 將關聯信息映射到 list 集合中,比如:查詢用戶權限范圍模塊及模塊下的菜單,可使用 collection 將模塊映射到模塊 list中,將菜單列表映射到模塊對象的菜單 list 屬性中,這樣的作的目的也是方便對查詢結果集進行遍歷查詢。

如果使用 resultType 無法將查詢結果映射到 list 集合中。


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com