主要內(nèi)容
1 高級(jí)映射
一對(duì)一
一對(duì)多
多對(duì)多
1 高級(jí)映射
2-1 訂單商品數(shù)據(jù)模型





數(shù)據(jù)模型分析思路:即拿到一個(gè)項(xiàng)目的數(shù)據(jù)庫的分析方法
1、每張表記錄的數(shù)據(jù)內(nèi)容
分模塊對(duì)每張表記錄的內(nèi)容進(jìn)行熟悉,相當(dāng)于你學(xué)習(xí)系統(tǒng)需求(功能)的過程。
2、每張表重要的字段設(shè)置
非空字段、外鍵字段
3、數(shù)據(jù)庫級(jí)別表與表之間的關(guān)系
外鍵關(guān)系
4、表與表之間的業(yè)務(wù)關(guān)系
在分析表與表之間的業(yè)務(wù)關(guān)系時(shí)一定要建立 在某個(gè)業(yè)務(wù)意義基礎(chǔ)上去分析。
2-2 數(shù)據(jù)模型分析

用戶表user:
記錄了購買商品的用戶信息
訂單表:orders
記錄了用戶所創(chuàng)建的訂單(購買商品的訂單)
訂單明細(xì)表:orderdetail:
記錄了訂單的詳細(xì)信息即購買商品的信息
商品表:items
記錄了商品信息
表與表之間的業(yè)務(wù)關(guān)系:
在分析表與表之間的業(yè)務(wù)關(guān)系時(shí)需要建立 在某個(gè)業(yè)務(wù)意義基礎(chǔ)上去分析。
先分析數(shù)據(jù)級(jí)別之間有關(guān)系的表之間的業(yè)務(wù)關(guān)系:
usre和orders:
user---->orders:一個(gè)用戶可以創(chuàng)建多個(gè)訂單,一對(duì)多
orders--->user:一個(gè)訂單只由一個(gè)用戶創(chuàng)建,一對(duì)一
orders和orderdetail:
orders---》orderdetail:一個(gè)訂單可以包括 多個(gè)訂單明細(xì),因?yàn)橐粋€(gè)訂單可以購買多個(gè)商品,每個(gè)商品的購買信息在orderdetail記錄,一對(duì)多關(guān)系
orderdetail--> orders:一個(gè)訂單明細(xì)只能包括在一個(gè)訂單中,一對(duì)一
orderdetail和itesm:
orderdetail---》itesms:一個(gè)訂單明細(xì)只對(duì)應(yīng)一個(gè)商品信息,一對(duì)一
items--> orderdetail:一個(gè)商品可以包括在多個(gè)訂單明細(xì) ,一對(duì)多
再分析數(shù)據(jù)庫級(jí)別沒有關(guān)系的表之間是否有業(yè)務(wù)關(guān)系:
orders和items:
orders和items之間可以通過orderdetail表建立 關(guān)系。
3 一對(duì)一查詢
需求:
查詢訂單信息,關(guān)聯(lián)查詢創(chuàng)建訂單的用戶信息
sql語句:
SELECT orders.*,user.username,user.sex,user.address FROM USER,orders WHERE orders.user_id = user.id

一個(gè)訂單對(duì)應(yīng)一個(gè)用戶
3-1 方式一 resultType
1 創(chuàng)建pojo
將上邊sql查詢的結(jié)果映射到pojo中,pojo中必須包括所有查詢列名。原始的Orders.java不能映射全部字段,需要新創(chuàng)建的pojo。創(chuàng)建一個(gè)pojo繼承包括查詢字段較多的po類。


2 mapper.xml
注意resultType="cn.itcast.mybatis.po.OrdersCustom與上面的pojo對(duì)應(yīng)
<select id="findOrdersUser" resultType="cn.itcast.mybatis.po.OrdersCustom">
SELECT
orders.*,
USER.username,
USER.sex,
USER.address
FROM
orders,
USER
WHERE orders.user_id = user.id
</select>
3 mapper.java
public interface OrdersMapperCustom {
//查詢訂單關(guān)聯(lián)查詢用戶信息
public List<OrdersCustom> findOrdersUser()throws Exception;
}
4 測(cè)試代碼
統(tǒng)一前置
private SqlSessionFactory sqlSessionFactory;
// 此方法是在執(zhí)行testFindUserById之前執(zhí)行
@Before
public void setUp() throws Exception {
// 創(chuàng)建sqlSessionFactory
// mybatis配置文件
String resource = "SqlMapConfig.xml";
// 得到配置文件流
InputStream inputStream = Resources.getResourceAsStream(resource);
// 創(chuàng)建會(huì)話工廠,傳入mybatis的配置文件信息
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void findOrdersUser() throws Exception{
SqlSession sqlSession = sqlSessionFactory.openSession();
// 創(chuàng)建代理對(duì)象
OrdersMapperCustom ordersMapperCustom = sqlSession
.getMapper(OrdersMapperCustom.class);
// 調(diào)用maper的方法
List<OrdersCustom> list = ordersMapperCustom.findOrdersUser();
System.out.println(list);
sqlSession.close();
}
3-2 方式二resultMap
映射的思路:使用resultMap將查詢結(jié)果中的訂單信息映射到Orders對(duì)象中,在orders類中添加User屬性,將關(guān)聯(lián)查詢出來的用戶信息映射到orders對(duì)象中的user屬性中。
1 在Orders類中添加user屬性

2 mapper.xml中定義resultMap
這個(gè)很重要,替代上面的pojo類
<resultMap type="cn.itcast.mybatis.po.Orders" id="OrdersUserResultMap">
<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"/>
<!-- 配置映射的關(guān)聯(lián)的用戶信息 -->
<!-- association:用于映射關(guān)聯(lián)查詢單個(gè)對(duì)象的信息
property:要將關(guān)聯(lián)查詢的用戶信息映射到Orders中哪個(gè)屬性
-->
<association property="user" javaType="cn.itcast.mybatis.po.User">
<!-- id:關(guān)聯(lián)查詢用戶的唯 一標(biāo)識(shí)
column:指定唯 一標(biāo)識(shí)用戶信息的列
javaType:映射到user的哪個(gè)屬性
-->
<id column="id" property="id"/>
<result column="username" property="username"/>
<result column="sex" property="sex"/>
<result column="address" property="address"/>
</association>
</resultMap>
3 mapper.java接口中定義方法
public List<Orders> findOrdersUserResultMap()throws Exception;
4 測(cè)試代碼
@Test
public void findOrdersUserResultMap() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
OrdersMapperCustom mapper = sqlSession.getMapper(OrdersMapperCustom.class);
List<Orders> ordersUser = mapper.findOrdersUserResultMap();
System.out.println(ordersUser);
sqlSession.close();
}
3-3 resultType和resultMap實(shí)現(xiàn)一對(duì)一查詢小結(jié)
實(shí)現(xiàn)一對(duì)一查詢:
resultType:使用resultType實(shí)現(xiàn)較為簡(jiǎn)單,如果pojo中沒有包括查詢出來的列名,需要增加列名對(duì)應(yīng)的屬性,即可完成映射。
如果沒有查詢結(jié)果的特殊要求建議使用resultType。
resultMap:需要單獨(dú)定義resultMap,實(shí)現(xiàn)有點(diǎn)麻煩,如果對(duì)查詢結(jié)果有特殊的要求,使用resultMap可以完成將關(guān)聯(lián)查詢映射pojo的屬性中。
resultMap可以實(shí)現(xiàn)延遲加載,resultType無法實(shí)現(xiàn)延遲加載。
4 多對(duì)多查詢
需求:查詢用戶及用戶購買商品信息
查詢主表是:用戶表
關(guān)聯(lián)表:由于用戶和商品沒有直接關(guān)聯(lián),通過訂單和訂單明細(xì)進(jìn)行關(guān)聯(lián),所以關(guān)聯(lián)表:
orders、orderdetail、items
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 orderdetail.orders_id=orders.id AND orderdetail.items_id = items.id
4-1 映射思路
將用戶信息映射到user中。
在user類中添加訂單列表屬性List<Orders> orderslist,將用戶創(chuàng)建的訂單映射到orderslist
在Orders中添加訂單明細(xì)列表屬性List<OrderDetail>orderdetials,將訂單的明細(xì)映射到orderdetials
在OrderDetail中添加Items屬性,將訂單明細(xì)所對(duì)應(yīng)的商品映射到Items。
4-2 pojo



4-3 mapper.xml
<!-- 查詢用戶及購買的商品 -->
<resultMap type="cn.itcast.mybatis.po.User" id="UserAndItemsResultMap">
<!-- 用戶信息 -->
<id column="user_id" property="id"/>
<result column="username" property="username"/>
<result column="sex" property="sex"/>
<result column="address" property="address"/>
<!-- 訂單信息
一個(gè)用戶對(duì)應(yīng)多個(gè)訂單,使用collection映射
-->
<collection property="ordersList" ofType="cn.itcast.mybatis.po.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"/>
<!-- 訂單明細(xì)
一個(gè)訂單包括 多個(gè)明細(xì)
-->
<collection property="orderdetails" ofType="cn.itcast.mybatis.po.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"/>
<!-- 商品信息
一個(gè)訂單明細(xì)對(duì)應(yīng)一個(gè)商品
-->
<association property="items" javaType="cn.itcast.mybatis.po.Items">
<id column="items_id" property="id"/>
<result column="items_name" property="name"/>
<result column="items_detail" property="detail"/>
<result column="items_price" property="price"/>
</association>
</collection>
</collection>
</resultMap>
4-4 接口定義方法
//查詢用戶購買商品信息
public List<User> findUserAndItemsResultMap()throws Exception;
4-5 測(cè)試類
@Test
public void findUserAndItemsResultMap() throws Exception{
SqlSession sqlSession = sqlSessionFactory.openSession();
// 創(chuàng)建代理對(duì)象
OrdersMapperCustom ordersMapperCustom = sqlSession
.getMapper(OrdersMapperCustom.class);
// 調(diào)用maper的方法
List<User> list = ordersMapperCustom.findUserAndItemsResultMap();
System.out.println(list);
sqlSession.close();
}
5 resultMap總結(jié)
resultType:
作用:
將查詢結(jié)果按照sql列名pojo屬性名一致性映射到pojo中。
場(chǎng)合:
常見一些明細(xì)記錄的展示,比如用戶購買商品明細(xì),將關(guān)聯(lián)查詢信息全部展示在頁面時(shí),此時(shí)可直接使用resultType將每一條記錄映射到pojo中,在前端頁面遍歷list(list中是pojo)即可。
resultMap:
使用association和collection完成一對(duì)一和一對(duì)多高級(jí)映射(對(duì)結(jié)果有特殊的映射要求)。
association:
作用:
將關(guān)聯(lián)查詢信息映射到一個(gè)pojo對(duì)象中。
場(chǎng)合:
為了方便查詢關(guān)聯(lián)信息可以使用association將關(guān)聯(lián)訂單信息映射為用戶對(duì)象的pojo屬性中,比如:查詢訂單及關(guān)聯(lián)用戶信息。
使用resultType無法將查詢結(jié)果映射到pojo對(duì)象的pojo屬性中,根據(jù)對(duì)結(jié)果集查詢遍歷的需要選擇使用resultType還是resultMap。
collection:
作用:
將關(guān)聯(lián)查詢信息映射到一個(gè)list集合中。
場(chǎng)合:
為了方便查詢遍歷關(guān)聯(lián)信息可以使用collection將關(guān)聯(lián)信息映射到list集合中,比如:查詢用戶權(quán)限范圍模塊及模塊下的菜單,可使用collection將模塊映射到模塊list中,將菜單列表映射到模塊對(duì)象的菜單list屬性中,這樣的作的目的也是方便對(duì)查詢結(jié)果集進(jìn)行遍歷查詢。
如果使用resultType無法將查詢結(jié)果映射到list集合中。
6 延遲加載
6-1 什么是延遲加載
resultMap可以實(shí)現(xiàn)高級(jí)映射(使用association、collection實(shí)現(xiàn)一對(duì)一及一對(duì)多映射),association、collection具備延遲加載功能。
需求:
如果查詢訂單并且關(guān)聯(lián)查詢用戶信息。如果先查詢訂單信息即可滿足要求,當(dāng)我們需要查詢用戶信息時(shí)再查詢用戶信息。把對(duì)用戶信息的按需去查詢就是延遲加載。
延遲加載:先從單表查詢、需要時(shí)再從關(guān)聯(lián)表去關(guān)聯(lián)查詢,大大提高 數(shù)據(jù)庫性能,因?yàn)椴樵儐伪硪汝P(guān)聯(lián)查詢多張表速度要快。
6-2 延遲加載配置
mybatis默認(rèn)沒有開啟延遲加載,需要在SqlMapConfig.xml中setting配置。
在mybatis核心配置文件中配置:
lazyLoadingEnabled、aggressiveLazyLoading

在SqlMapConfig.xml中配置:
<settings>
<!-- 打開延遲加載 的開關(guān) -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 將積極加載改為消極加載即按需要加載 -->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
6-3 使用association實(shí)現(xiàn)延遲加載
查詢訂單并且關(guān)聯(lián)查詢用戶信息
1 mapper.xml
需要定義兩個(gè)mapper的方法對(duì)應(yīng)的statement。
(1)只查詢訂單信息
SELECT * FROM orders
在查詢訂單的statement中使用association去延遲加載(執(zhí)行)下邊的satatement(關(guān)聯(lián)查詢用戶信息)
<!-- 查詢訂單關(guān)聯(lián)查詢用戶,用戶信息需要延遲加載 -->
<select id="findOrdersUserLazyLoading" resultMap="OrdersUserLazyLoadingResultMap">
SELECT * FROM orders
</select>
(2)關(guān)聯(lián)查詢用戶信息
通過上邊查詢到的訂單信息中user_id去關(guān)聯(lián)查詢用戶信息
使用association中的select指定延遲加載去執(zhí)行的statement的id。
使用UserMapper.xml中的findUserById
<!-- 延遲加載的resultMap -->
<resultMap type="cn.itcast.mybatis.po.Orders" id="OrdersUserLazyLoadingResultMap">
<!--對(duì)訂單信息進(jìn)行映射配置 -->
<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"/>
<!-- 實(shí)現(xiàn)對(duì)用戶信息進(jìn)行延遲加載
select:指定延遲加載需要執(zhí)行的statement的id(是根據(jù)user_id查詢用戶信息的statement)
要使用userMapper.xml中findUserById完成根據(jù)用戶id(user_id)用戶信息的查詢,如果findUserById不在本mapper中需要前邊加namespace
column:訂單信息中關(guān)聯(lián)用戶信息查詢的列,是user_id
關(guān)聯(lián)查詢的sql理解為:
SELECT orders.*,
(SELECT username FROM USER WHERE orders.user_id = user.id)username,
(SELECT sex FROM USER WHERE orders.user_id = user.id)sex
FROM orders
-->
<association property="user" javaType="cn.itcast.mybatis.po.User"
select="cn.itcast.mybatis.mapper.UserMapper.findUserId" column="user_id">
<!-- 實(shí)現(xiàn)對(duì)用戶信息進(jìn)行延遲加載 -->
</association>
</resultMap>
上邊先去執(zhí)行findOrdersUserLazyLoading,當(dāng)需要去查詢用戶的時(shí)候再去執(zhí)行findUserById,通過resultMap的定義將延遲加載執(zhí)行配置起來。
2 測(cè)試
1、執(zhí)行上邊mapper方法(findOrdersUserLazyLoading),內(nèi)部去調(diào)用cn.itcast.mybatis.mapper.OrdersMapperCustom中的findOrdersUserLazyLoading只查詢orders信息(單表)。
2、在程序中去遍歷上一步驟查詢出的List<Orders>,當(dāng)我們調(diào)用Orders中的getUser方法時(shí),開始進(jìn)行延遲加載。
3、延遲加載,去調(diào)用UserMapper.xml中findUserbyId這個(gè)方法獲取用戶信息。
代碼如下
@Test
public void testFindOrdersUserLazyLoading() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();// 創(chuàng)建代理對(duì)象
OrdersMapperCustom ordersMapperCustom = sqlSession
.getMapper(OrdersMapperCustom.class);
// 查詢訂單信息(單表)
List<Orders> list = ordersMapperCustom.findOrdersUserLazyLoading();
// 遍歷上邊的訂單列表
for (Orders orders : list) {
// 執(zhí)行g(shù)etUser()去查詢用戶信息,這里實(shí)現(xiàn)按需加載
User user = orders.getUser();
System.out.println(user);
}
}
6-4 延遲加載思考
不使用mybatis提供的association及collection中的延遲加載功能,如何實(shí)現(xiàn)延遲加載??
實(shí)現(xiàn)方法如下:
定義兩個(gè)mapper方法:
1、查詢訂單列表
2、根據(jù)用戶id查詢用戶信息
實(shí)現(xiàn)思路:
先去查詢第一個(gè)mapper方法,獲取訂單信息列表
在程序中(service),按需去調(diào)用第二個(gè)mapper方法去查詢用戶信息。
總之:
使用延遲加載方法,先去查詢簡(jiǎn)單的sql(最好單表,也可以關(guān)聯(lián)查詢),再去按需要加載關(guān)聯(lián)查詢的其它信息。