什么是延遲加載
舉個(gè)例子:如果查詢訂單并且關(guān)聯(lián)查詢用戶信息。如果先查詢訂單信息即可滿足要求,當(dāng)我們需要查詢用戶信息時(shí)再查詢用戶信息。把對(duì)用戶信息的按需去查詢就是延遲加載枣氧。 所以延遲加載即先從單表查詢、需要時(shí)再?gòu)年P(guān)聯(lián)表去關(guān)聯(lián)查詢垮刹,大大提高數(shù)據(jù)庫(kù)性能达吞,因?yàn)椴樵儐伪硪汝P(guān)聯(lián)查詢多張表速度要快。
我們來對(duì)比一下:
關(guān)聯(lián)查詢:SELECT orders.*, user.username FROM orders, USER WHERE orders.user_id = user.id
延遲加載相當(dāng)于:
SELECT orders.*,
(SELECT username FROM USER WHERE orders.user_id = user.id)username FROM orders
所以這就比較直觀了危纫,也就是說宗挥,我把關(guān)聯(lián)查詢分兩次來做,而不是一次性查出所有的种蝶。第一步只查詢單表orders契耿,必然會(huì)查出orders中的一個(gè)user_id字段,然后我再根據(jù)這個(gè)user_id查user表螃征,也是單表查詢搪桂。下面來總結(jié)一下如何使用這個(gè)延遲加載.
使用association實(shí)現(xiàn)延遲加載
前面博文中總結(jié)了resultMap可以實(shí)現(xiàn)高級(jí)映射(使用association、collection實(shí)現(xiàn)一對(duì)一及一對(duì)多映射)盯滚,其實(shí)association和collection還具備延遲加載的功能踢械,這里我就拿association來說明,collection和association使用的方法都是一樣的魄藕。需求就是上面提到的内列,查詢訂單并且關(guān)聯(lián)查詢用戶,查詢用戶使用延遲加載背率。
由上面的分析可知话瞧,延遲加載要查詢兩次,第二次是按需查詢寝姿,之前一對(duì)一關(guān)聯(lián)查詢的時(shí)候只需要查一次交排,把訂單和用戶信息都查出來了,所以只要寫一個(gè)mapper即可饵筑,但是延遲加載查兩次埃篓,所以理所當(dāng)然要有兩個(gè)mapper。(例如Orders表中有外鍵來引用Users表中的主鍵,所以我們查詢Orders表,在使用外鍵來查詢Users表)
兩個(gè)mapper.xml
需要定義兩個(gè)mapper的方法對(duì)應(yīng)的statement根资。先來分析一下思路:
1.只查詢訂單信息的statement架专,使用resultMap
2.通過查詢到的訂單信息中的user_id去查詢用戶信息的statement同窘,得到用戶
3.定義的resultMap將兩者關(guān)聯(lián)起來,即用訂單信息user_id去查用戶
下面來實(shí)現(xiàn)這個(gè)思路:
1. 只查詢訂單信息的statement:
<select id="findOrdersUserLazyLoading" resultMap="OrdersUserLazyLoadingResultMap">
SELECT * FROM orders
</select>
2. 只查詢用戶信息的statement:
<select id="findUserById" parameterType="int" resultType="user">
select * from user where id = #{id}
</select>
3. 定義上面那個(gè)resultMap:
2.2 延遲加載的配置
mybatis默認(rèn)沒有開啟延遲加載胶征,需要在SqlMapConfig.xml中setting配置塞椎。前面一篇博文中提到SqlMapConfig.xml中的一些配置桨仿,有一個(gè)<settings>睛低,當(dāng)時(shí)沒說,這里就派上用場(chǎng)了服傍,可以通過這個(gè)標(biāo)簽來配置一下延遲加載钱雷。
<settings>
<!-- 打開延遲加載的開關(guān) -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 將積極加載改為消極加載,即延遲加載 -->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
2.3 mapper.java
別忘了寫mapper接口:
public interface UserMapperOrders {
//省去不相關(guān)代碼
//查詢訂單吹零,關(guān)聯(lián)用戶查詢罩抗,用戶查詢用的是延遲加載
public List<Orders> findOrdersUserLazyLoading() throws Exception;
}
到此為止,延遲加載就做完了灿椅,下面來測(cè)試一下:
@Test
public void testFindOrdersUserLazyLoading() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapperOrders userMapperOrders = sqlSession.getMapper(UserMapperOrders.class);
//查詢訂單表(單表)
List<Orders> list = userMapperOrders.findOrdersUserLazyLoading();
//遍歷上邊的訂單列表
for(Orders orders : list) {
//執(zhí)行g(shù)etUser()去查詢用戶信息套蒂,這里實(shí)現(xiàn)按需加載
User user = orders.getUser();
System.out.println(user);
}
}
看一下執(zhí)行結(jié)果:
執(zhí)行結(jié)果很明顯,使用了延遲加載茫蛹,將關(guān)聯(lián)查詢分成了兩次單表查詢操刀,但是有個(gè)奇怪的地方,就是第二次查用戶的時(shí)候婴洼,并沒有發(fā)sql骨坑,而是直接就拿到了,其實(shí)這就是mybatis中的一級(jí)緩存.