一、什么是延遲加載
- 延遲加載:先從單表查詢(xún)、需要時(shí)再?gòu)年P(guān)聯(lián)表去關(guān)聯(lián)查詢(xún),大大提高數(shù)據(jù)庫(kù)性能。
-
resultMap可以實(shí)現(xiàn)高級(jí)映射(使用association、collection實(shí)現(xiàn)一對(duì)一和一對(duì)多映射),association、collection具備延遲加載的功能。 - 如果現(xiàn)在的需求:
查詢(xún)訂單并且關(guān)聯(lián)查詢(xún)用戶(hù)信息。如果先查詢(xún)訂單信息即可滿(mǎn)足要求,當(dāng)我們需要用戶(hù)信息時(shí)再查詢(xún)用戶(hù)信息。把對(duì)用戶(hù)信息的按需查詢(xún)就是延遲加載。
二、使用association實(shí)現(xiàn)延遲加載
需求在上面已經(jīng)給出。(工程mybatis12)
2.1 mapper.xml
- 1.先只查詢(xún)訂單信息
SELECT * FROM orders
在查詢(xún)訂單的statement中使用association去延遲加載(執(zhí)行)下面的statement。
- 2.關(guān)聯(lián)查詢(xún)用戶(hù)信息
通過(guò)上面查詢(xún)到的訂單信息中的user_id去關(guān)聯(lián)查詢(xún)用戶(hù)信息
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
說(shuō)明:上面的sql只是說(shuō)明,語(yǔ)法是不正確的。也就是說(shuō)我們可以通過(guò)訂單信息中的user_id去關(guān)聯(lián)查詢(xún)用戶(hù)的各項(xiàng)信息。
OrdersMapper.xml
<!-- 延遲加載的resultMap -->
<resultMap type="Orders" id="OrdersUserLazyResultMap">
<!-- 首先需要對(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"/>
<!-- 對(duì)用戶(hù)信息進(jìn)行延遲加載
select:指定延遲加載要執(zhí)行的sql語(yǔ)句(statement),這里根據(jù)user_id查詢(xún)用戶(hù)信息的statement,
要使用UserMapper.xml中的findUserById來(lái)完成根據(jù)用戶(hù)id(user_id)的用戶(hù)信息查詢(xún),需要使用命名空間
column: 訂單信息中關(guān)聯(lián)用戶(hù)信息查詢(xún)的列,是user_id
關(guān)聯(lián)查詢(xú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="User" select="cn.itcast.mapper.UserMapper.findUserById" column="user_id">
</association>
</resultMap>
<!-- 查詢(xún)訂單,關(guān)聯(lián)查詢(xún)用戶(hù),用戶(hù)信息需要延遲加載 -->
<select id="findOrdersUserLazy" resultMap="OrdersUserLazyResultMap">
SELECT * FROM orders
</select>
說(shuō)明:從上面的注釋中我們可以明確的知道首先我們是查詢(xún)訂單信息(單表),在resultMap中我們使用association的延遲加載功能延遲加載用戶(hù)信息,而用戶(hù)信息的查詢(xún)我們可以使用之前配置過(guò)的查詢(xún)statement。
注意:在配置延遲加載的時(shí)候我們使用了之前的查詢(xún)select="cn.itcast.mapper.UserMapper.findUserById",由于不再同一個(gè)mapper.xml中,所以要加上命名空間:
UserMapper.xml
<!-- 查詢(xún),通過(guò)用戶(hù)id進(jìn)行查詢(xún)-->
<select id="findUserById" parameterType="java.lang.Integer" resultType="User">
SELECT * FROM USER WHERE id = #{value}
</select>
2.2 配置延遲加載功能
延遲加載配置,默認(rèn)是沒(méi)有開(kāi)啟延遲加載的,需要在全局配置文件SqlMapConfig.xml的settings中進(jìn)行配置。
| 設(shè)置項(xiàng) | 描述 | 允許值 | 默認(rèn)值 |
|---|---|---|---|
lazyLoadingEnabled |
全局性設(shè)置懶加載。如果設(shè)置為"false",則所有相關(guān)聯(lián)的都會(huì)被初始化加載 |
true/false |
false |
aggressiveLazyLoading |
當(dāng)設(shè)置為"true"的時(shí)候,懶加載的對(duì)象可能被任何懶屬性全部加載。否咋,每個(gè)屬性都按需加載。 |
true/false |
true |
配置:
<settings>
<!-- 打開(kāi)延遲加載的開(kāi)關(guān),再將積極加載改為消極加載(即按需加載) -->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
2.3 mapper.java
OrdersMapper.java
//查詢(xún)訂單,關(guān)聯(lián)查詢(xún)用戶(hù),其中用戶(hù)信息是延遲加載
public List<Orders> findOrdersUserLazy() throws Exception;
2.4 測(cè)試
OrdersMapperTest.java
//查詢(xún)訂單關(guān)聯(lián)查詢(xún)用戶(hù)信息,其中用戶(hù)信息使用延遲加載
@Test
public void testFindOrdersUserLazy() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
//創(chuàng)建代理對(duì)象
OrdersMapper orders = sqlSession.getMapper(OrdersMapper.class);
//查詢(xún)訂單信息(單表)
List<Orders> list = orders.findOrdersUserLazy();
//遍歷上面的訂單列表
for(Orders order : list){
User user = order.getUser();//這里實(shí)現(xiàn)按需加載
System.out.println(user);
}
System.out.println(list.size());
sqlSession.close();
}
說(shuō)明:
- 1.執(zhí)行上面的
mapper接口中的方法,內(nèi)部調(diào)用findOrdersUserLazy,只查詢(xún)orders信息(單表) - 2.在程序中去遍歷
List<Orders>,當(dāng)我們調(diào)用Orders中的getUser方法時(shí),就開(kāi)始進(jìn)行延遲加載。 - 3.延遲加載去調(diào)用
findUserById這個(gè)方法獲取用戶(hù)信息。 - 測(cè)試結(jié)果為:
1
可以看到當(dāng)用戶(hù)id一樣時(shí),是不會(huì)重復(fù)發(fā)送sql語(yǔ)句的,這就是后面要將的緩存的概念。
2.5 如果我們不使用mybatis提供的延遲加載,我們?nèi)绾螌?shí)現(xiàn)延遲加載?
- 實(shí)現(xiàn)方法如下:
定義兩個(gè)mapper方法- 查詢(xún)訂單列表
- 根據(jù)用戶(hù)
id查詢(xún)用戶(hù)信息
- 根據(jù)用戶(hù)
- 實(shí)現(xiàn)思路:
先查詢(xún)第一個(gè)mapper的方法得到訂單信息列表,在程序中(service類(lèi)中),按需去調(diào)用第二個(gè)mapper方法去查詢(xún)用戶(hù)信息。當(dāng)然這也是mybatis實(shí)現(xiàn)延遲加載的原理。
總結(jié):使用延遲加載方法,先去查詢(xún)簡(jiǎn)單的sql(最好是單表,也可以是關(guān)聯(lián)查詢(xún)),然后再去按需加載關(guān)聯(lián)查詢(xún)的其他信息。最后對(duì)于collection實(shí)現(xiàn)延遲加載的方式和上面是一樣的,這里不再細(xì)說(shuō)。
