學習hibernate的時候,小編已經接觸多各種映射,mybatis中映射有到底是如何運轉的,今天這篇博文,小編主要來簡單的介紹一下mybatis中的高級映射,包括一對一、一對多、多對多,希望多有需要的小伙伴有幫助,小編主要從四個方面進行介紹,訂單商品數據模型、一對一查詢、一對多查詢、多對多查詢。
一、訂單商品數據模型
1、數據庫執行腳本,如下所示:
<span style="font-family:Comic Sans MS;font-size:18px;">CREATE TABLE items ( id INT NOT NULL AUTO_INCREMENT, itemsname 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) ) DEFAULT CHARSET=utf8; /*Table structure for table `orderdetail` */ CREATE TABLE orderdetail ( id INT NOT NULL AUTO_INCREMENT, orders_id INT NOT NULL COMMENT '訂單id', items_id INT NOT NULL COMMENT '商品id', items_num INT 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 ) DEFAULT CHARSET=utf8; /*Table structure for table `orders` */ CREATE TABLE orders ( id INT NOT NULL AUTO_INCREMENT, user_id INT NOT NULL COMMENT '下單用戶id', number VARCHAR(30) 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 `t_user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION ) DEFAULT CHARSET=utf8; /*Table structure for table `t_user` */ CREATE TABLE t_user ( id INT NOT NULL AUTO_INCREMENT, username VARCHAR(32) NOT NULL COMMENT '用戶名稱', birthday DATE DEFAULT NULL COMMENT '生日', sex CHAR(1) DEFAULT NULL COMMENT '性別', address VARCHAR(256) DEFAULT NULL COMMENT '地址', PRIMARY KEY (`id`) ) DEFAULT CHARSET=utf8; </span>
測試數據代碼
<span style="font-family:Comic Sans MS;font-size:18px;">/*Data for the table `items` */ INSERT INTO items(itemsname,price,detail,pic,createtime) VALUES ('台式機',3000.0,'該電腦質量非常好!',NULL,'2015-07-07 13:28:53'), ('筆記本',6000.0,'筆記本性能好,質量好!',NULL,'2015-07-08 13:22:57'), ('背包',200.0,'名牌背包,容量大質量好!',NULL,'2015-07-010 13:25:02'); /*Data for the table `orderdetail` */ INSERT INTO `orderdetail`(`orders_id`,`items_id`,`items_num`) VALUES (1,1,1), (1,2,3), (2,3,4), (3,2,3); /*Data for the table `orders` */ INSERT INTO `orders`(`user_id`,`number`,`createtime`,`note`) VALUES (1,'1000010','2015-06-04 13:22:35',NULL), (1,'1000011','2015-07-08 13:22:41',NULL), (2,'1000012','2015-07-17 14:13:23',NULL), (3,'1000012','2015-07-16 18:13:23',NULL), (4,'1000012','2015-07-15 19:13:23',NULL), (5,'1000012','2015-07-14 17:13:23',NULL), (6,'1000012','2015-07-13 16:13:23',NULL); /*Data for the table `user` */ INSERT INTO `t_user`(`username`,`birthday`,`sex`,`address`) VALUES ('王五',NULL,'2',NULL), ('張三','2014-07-10','1','北京市'), ('張小明',NULL,'1','河南鄭州'), ('陳小明',NULL,'1','河南鄭州'), ('張三豐',NULL,'1','河南鄭州'), ('陳小明',NULL,'1','河南鄭州'), ('王五',NULL,NULL,NULL), ('小A','2015-06-27','2','北京'), ('小B','2015-06-27','2','北京'), ('小C','2015-06-27','1','北京'), ('小D','2015-06-27','2','北京'); </span>2、數據模型分析思路
(1).每張表記錄的數據內容:分模塊對每張表記錄的內容進行熟悉,相當於你學習系統需求(功能)的過程;
(2).每張表重要的字段設置:非空字段、外鍵字段;
(3).數據庫級別表與表之間的關係:外鍵關係;
(4).表與表之間的業務關係:在分析表與表之間的業務關係時一定要建立在某個業務意義基礎上去分析。
3、針對訂單商品模型的數據庫思路分析,如下圖所示:
二、一對一查詢
2.1、需求:查詢訂單信息,關聯查詢用戶信息
2.2、resultType實現
2.2.1sql語句
確定查詢的主表:訂單表,確定查詢的關聯表,用戶表,代碼如下所示:
<span style="font-family:Comic Sans MS;font-size:18px;">SELECT t1.*, t2.username, t2.sex, t2.address FROM orders t1, t_user t2 WHERE t1.user_id=t2.id </span>
2.2.2創建entity實體
用戶實體User.java,代碼如下所示:
<span style="font-family:Comic Sans MS;font-size:18px;">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 ...... } </span>訂單實體orders.java
<span style="font-family:Comic Sans MS;font-size:18px;">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 ...... } </span>商品實體:items.java
<span style="font-family:Comic Sans MS;font-size:18px;">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 ...... } </span>訂單明細實體orderDetail.java
<span style="font-family:Comic Sans MS;font-size:18px;">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 ...... } </span>創建一個包裝類,將查詢到的信息全部映射到此類OrdersCustom.java
<span style="font-family:Comic Sans MS;font-size:18px;">/** * @ClassName: OrdersCustom * @Description: TODO(訂單的擴展類,通過此類映射訂單和用戶的查詢結果,讓此類繼承字段較多的實體類) * @author: 丁國華*/ public class OrdersCustom extends Orders { // 添加用戶的屬性private String username; private String sex; private String address; // getter and setter...... } </span>2.2.3創建OrderscCustomMapper.java,代碼如下所示:
<span style="font-family:Comic Sans MS;font-size:18px;">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(); } </span>2.2.4創建OrdersCustomMapper.xml和上面對應的接口名稱一致,一邊通過mapper接口加載配置文件,代碼如下所示:
<span style="font-family:Comic Sans MS;font-size:18px;"><?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> </span>
2.3resultMap實現
2.3.1sql語句同上
2.3.2resultMap映射思路:
使用resultMap將查詢結果中的訂單信息映射到Orders對像中,在orders類中添加User屬性,將關聯查詢出來的用戶信息映射到orders對像中的user屬性中(上面orders實體中已經添加)。
2.3.3 ordersCustomMapper.xml
1、定義resultMap,代碼如下所示:
<span style="font-family:Comic Sans MS;font-size:18px;"><!-- 定義查詢訂單關聯用戶的resultMap,將整個的查詢結果映射到com.mybatis.entity.Orders中--> <resultMap type="com.mybatis.entity.Orders" id="OrdersUserResultMap"> <!-- 配置映射的訂單信息--> <!-- id:查詢列中的唯一標識,訂單信息中的唯一標識,如果多列組成唯一標識(如:一般數據庫設計中的字典表使用聯合主鍵),就需要配置多個id column:訂單信息的唯一標識列property:訂單信息的唯一標識列所映射到orders中的那個屬性(假如:數據庫中orders表中的主鍵為orders_id,而實體屬性名稱為ordersId, 則這個配置應為<id column="orders_id" property="ordersId"/>,類似hibernate實體映射文件配置)。 --> <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"/> <!-- 配置映射的關聯用戶信息--> <!--association:用於映射關聯查詢單個對象的信息property:要將關聯查詢的用戶信息映射到Orders中那個屬性--> <association property="user" javaType="com.mybatis.entity.User"> <!-- id:關聯查詢用戶的唯一標識column:指定唯一標識用戶信息的列property:映射到user的那個屬性--> <id column="user_id" property="id"/> <result column="username" property="username"/> <result column="sex" property="sex"/> <result column="address" property="address"/> </association> </resultMap> </span>
2、statement定義,代碼如下所示:
<span style="font-family:Comic Sans MS;font-size:18px;"><!-- 查詢訂單,關聯查詢用戶信息,使用resultMap實現--> <select id="findOrdersUserResultMap" resultMap="OrdersUserResultMap"> SELECT t1.*, t2.username, t2.sex, t2.address FROM orders t1, t_user t2 WHERE t1.user_id=t2.id </select></span>
3、OrderCustomMapper.java接口中添加下面的方法:
<span style="font-family:Comic Sans MS;font-size:18px;">/** 查詢訂單關聯查詢用戶信息,使用reslutMap實現*/ public List<Orders>findOrdersUserResultMap(); </span>
4、對resultType和resultMap實現的junit測試,代碼如下所示:
<span style="font-family:Comic Sans MS;font-size:18px;">package com.mybatis.test; import java.io.InputStream; import java.util.List; 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 com.mybatis.entity.Orders; import com.mybatis.entity.OrdersCustom; import com.mybatis.mapper.OrdersCustomMapper; public class OrdersCustomMapperTest { private SqlSessionFactory sqlSessionFactory; // 此方法是在執行findUserByIdTest之前執行@Before public void setUp() throws Exception { String resource = "SqlMapConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); // 創建SqlSessionFcatory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } // 查詢訂單,關聯查詢用戶信息,使用resultType實現的測試@Test public void TestFindOrdersUser() { SqlSession sqlSession = sqlSessionFactory.openSession(); // 創建代理對象OrdersCustomMapper oc = sqlSession.getMapper(OrdersCustomMapper.class); // 調用mapper的方法List<OrdersCustom> list = oc.findOrdersUser(); System.out.println(list); sqlSession.close(); } // 查詢訂單,關聯查詢用戶信息,使用resultMap實現的測試@Test public void TestFindOrdersUserResultMap() { SqlSession sqlSession = sqlSessionFactory.openSession(); // 創建代理對象OrdersCustomMapper oc = sqlSession.getMapper(OrdersCustomMapper.class); // 調用mapper的方法List<Orders> list = oc.findOrdersUserResultMap(); System.out.println(list); sqlSession.close(); }} </span>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中添加如下
<span style="font-family:Comic Sans MS;font-size:18px;"><!-- 查詢訂單關聯查詢用戶及訂單明細--> <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> </span>
resultMap的定義同樣添加到ordersCustomMapper.xml
<span style="font-family:Comic Sans MS;font-size:18px;"><!-- 查詢訂單(關聯用戶)及訂單明細的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> </span>
3.4 在OrderCustomeMapper.java接口類中添加一個方法,代碼如下所示:
<span style="font-family:Comic Sans MS;font-size:18px;">/**查詢訂單(關聯用戶)以及訂單明細*/ public List<OrderDetail>findOrdersAndOrderDetailResultMap(); </span>
3.5 在Junit測試類中添加測試方法,代碼如下所示:
<span style="font-family:Comic Sans MS;font-size:18px;">// 查詢訂單(關聯用戶)以及訂單明細的測試@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(); } </span>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添加如下代碼:
<span style="font-family:Comic Sans MS;font-size:18px;"><!-- 查詢用戶即購買的商品信息的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> </span>
4.4 在OrderCustomMapper.java中添加如下方法:
<span style="font-family:Comic Sans MS;font-size:18px;"> /** 查詢用戶及用戶所購買的商品信息*/ public List<User> findUserAndItemsResultMap(); </span>
4.5 在Junit測試中添加測試方法,代碼如下所示:
<span style="font-family:Comic Sans MS;font-size:18px;">// 查詢用戶及用戶購買的商品的信息@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(); } </span> 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集合中。
以上所述是小編給大家介紹的Mybatis中的高級映射一對一、一對多、多對多,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對武林網網站的支持!