一文看懂Mybatis中的延遲加載
1. 延遲加載簡(jiǎn)介
MyBatis中的延遲加載,也稱為懶加載,是指在進(jìn)行表的關(guān)聯(lián)查詢時(shí),按照設(shè)置延遲規(guī)則推遲對(duì)關(guān)聯(lián)對(duì)象的select查詢。例如在進(jìn)行一對(duì)多查詢的時(shí)候,只查詢出一方,當(dāng)程序中需要多方的數(shù)據(jù)時(shí),mybatis再發(fā)出sql語(yǔ)句進(jìn)行查詢,這樣子延遲加載就可以的減少數(shù)據(jù)庫(kù)壓力。MyBatis 的延遲加載只是對(duì)關(guān)聯(lián)對(duì)象的查詢有遲延設(shè)置,對(duì)于主加載對(duì)象都是直接執(zhí)行查詢語(yǔ)句的。
好處:
先從單表查詢,需要時(shí)再?gòu)年P(guān)聯(lián)表去關(guān)聯(lián)查詢,大大提高數(shù)據(jù)庫(kù)性能,因?yàn)椴樵儐伪硪汝P(guān)聯(lián)查詢多張表速度要快。
壞處:
因?yàn)橹挥挟?dāng)需要用到數(shù)據(jù)時(shí),才會(huì)進(jìn)行數(shù)據(jù)庫(kù)查詢,這樣在大批量數(shù)據(jù)查詢時(shí),因?yàn)椴樵児ぷ饕惨臅r(shí)間,所以可能造成用戶等待時(shí)間變長(zhǎng),造成用戶體驗(yàn)下降。
2. 關(guān)聯(lián)對(duì)象加載時(shí)機(jī)
MyBatis根據(jù)對(duì)關(guān)聯(lián)對(duì)象查詢的select語(yǔ)句的執(zhí)行時(shí)機(jī),分為三種類型:直接加載、侵入式延遲加載與深度延遲加載。
- 直接加載:執(zhí)行完對(duì)主加載對(duì)象的 select 語(yǔ)句,馬上執(zhí)行對(duì)關(guān)聯(lián)對(duì)象的 select 查詢。
- 侵入式延遲: 執(zhí)行對(duì)主加載對(duì)象的查詢時(shí),不會(huì)執(zhí)行對(duì)關(guān)聯(lián)對(duì)象的查詢。但當(dāng)要訪問(wèn)主加載對(duì)象的詳情屬性時(shí),就會(huì)馬上執(zhí)行關(guān)聯(lián)對(duì)象的select查詢。
- 深度延遲: 執(zhí)行對(duì)主加載對(duì)象的查詢時(shí),不會(huì)執(zhí)行對(duì)關(guān)聯(lián)對(duì)象的查詢。訪問(wèn)主加載對(duì)象的詳情時(shí)也不會(huì)執(zhí)行關(guān)聯(lián)對(duì)象的select查詢。只有當(dāng)真正訪問(wèn)關(guān)聯(lián)對(duì)象的詳情時(shí),才會(huì)執(zhí)行對(duì)關(guān)聯(lián)對(duì)象的 select 查詢。
需要注意的是, 延遲加載的應(yīng)用要求,關(guān)聯(lián)對(duì)象的查詢與主加載對(duì)象的查詢必須是分別進(jìn)行的 select 語(yǔ)句,不能是使用多表連接所進(jìn)行的select查詢。因?yàn)槎啾磉B接查詢,其實(shí)質(zhì)是對(duì)一張表的查詢,對(duì)由多個(gè)表連接后形成的一張表的查詢。會(huì)一次性將多張表的所有信息查詢出來(lái)。
MyBatis中對(duì)于延遲加載設(shè)置,只對(duì)于resultMap中的collection和association起作用,可以應(yīng)用到一對(duì)一、一對(duì)多、多對(duì)一、多對(duì)多的所有關(guān)聯(lián)關(guān)系查詢中。
下面以一對(duì)多關(guān)聯(lián)關(guān)系查詢?yōu)槔?,講解 MyBatis 中的延遲加載應(yīng)用。
3. 直接加載
主配置文件SqlMapConfig.xml中設(shè)置lazyLoadingEnabled為false,默認(rèn)為false。(因?yàn)槟J(rèn)式false,所以也可以不設(shè)置lazyLoadingEnabled)
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 配置properties --> <properties resource="jdbcConfig.properties"></properties> <!-- 配置參數(shù) --> <settings> <!-- 關(guān)閉mybatis支持延遲加載 --> <setting name="lazyLoadingEnabled" value="false"/> </settings> <!-- 使用typeAliases配置別名,它只能配置domain中類的別名 --> <typeAliases> <package name="com.siyi.domain"></package> </typeAliases> <!-- 配置環(huán)境 --> <environments default="mysql"> <!-- 配置mysql的環(huán)境 --> <environment id="mysql"> <!-- 配置事務(wù) --> <transactionManager type="JDBC"></transactionManager> <!-- 配置連接池 --> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </dataSource> </environment> </environments> <!-- 映射配置文件 --> <mappers> <mapper resource="com/siyi/dao/IUserDao.xml"/> <mapper resource="com/siyi/dao/IAccountDao.xml"/> </mappers> </configuration>
dao映射配置文件
<?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"> <mapper namespace="com.siyi.dao.IUSerDao"> <!-- 定義User的resultMap --> <resultMap id="userAccountMap" type="user"> <id property="id" column="id"/> <result property="username" column="username"/> <result property="address" column="address"/> <result property="sex" column="sex"/> <result property="birthday" column="birthday"/> <collection property="accounts" ofType="account" select="com.siyi.dao.IAccountDao.findAccountByUid" column="id"/> </resultMap> <!-- 查詢所有 --> <select id="findAll" resultMap="userAccountMap"> <!-- select * from user; --> select * from user </select> </mapper>
測(cè)試
package com.siyi.test; import com.siyi.dao.IUSerDao; import com.siyi.domain.User; 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.After; import org.junit.Before; import org.junit.Test; import java.io.IOException; import java.io.InputStream; import java.util.List; public class UserTest { private InputStream in; private SqlSession session; private IUSerDao iuSerDao; @Before//用于在測(cè)試方法執(zhí)行之前執(zhí)行 public void init() throws IOException { //1.讀取配置文件生成字節(jié)輸入流 in = Resources.getResourceAsStream("SqlMapConfig.xml"); //2.獲取SqlSessionFactory對(duì)象 SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(in); //3.獲取SqlSession對(duì)象 session = factory.openSession(true); //4.獲取DAO的代理對(duì)象 iuSerDao = session.getMapper(IUSerDao.class); } @After//用于在測(cè)試方法之后執(zhí)行 public void destroy() throws IOException { //事務(wù)提交 //session.commit(); //釋放資源 session.close(); in.close(); } /** * 測(cè)試查詢所有 * @throws IOException */ @Test public void testFindAll() throws IOException { //5.執(zhí)行查詢所有方法 List<User> users = iuSerDao.findAll(); } }
運(yùn)行過(guò)程中就查詢了所有的信息:
4. 侵入式延遲加載
主配置文件SqlMapConfig.xml中設(shè)置lazyLoadingEnabled為true,默認(rèn)為false,并且將aggressiveLazyLoading設(shè)置為true。(aggressiveLazyLoading默認(rèn)值為false (在 3.4.1 及之前的版本中默認(rèn)為 true))
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 配置properties --> <properties resource="jdbcConfig.properties"></properties> <!-- 配置參數(shù) --> <settings> <!-- 開(kāi)啟mybatis支持延遲加載 --> <setting name="lazyLoadingEnabled" value="false"/> <setting name="aggressiveLazyLoading" value="true"/> </settings> <!-- 使用typeAliases配置別名,它只能配置domain中類的別名 --> <typeAliases> <package name="com.siyi.domain"></package> </typeAliases> <!-- 配置環(huán)境 --> <environments default="mysql"> <!-- 配置mysql的環(huán)境 --> <environment id="mysql"> <!-- 配置事務(wù) --> <transactionManager type="JDBC"></transactionManager> <!-- 配置連接池 --> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </dataSource> </environment> </environments> <!-- 映射配置文件 --> <mappers> <mapper resource="com/siyi/dao/IUserDao.xml"/> <mapper resource="com/siyi/dao/IAccountDao.xml"/> </mappers> </configuration>
dao映射配置文件不變
測(cè)試
package com.siyi.test; import com.siyi.dao.IUSerDao; import com.siyi.domain.User; 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.After; import org.junit.Before; import org.junit.Test; import java.io.IOException; import java.io.InputStream; import java.util.List; public class UserTest { private InputStream in; private SqlSession session; private IUSerDao iuSerDao; @Before//用于在測(cè)試方法執(zhí)行之前執(zhí)行 public void init() throws IOException { //1.讀取配置文件生成字節(jié)輸入流 in = Resources.getResourceAsStream("SqlMapConfig.xml"); //2.獲取SqlSessionFactory對(duì)象 SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(in); //3.獲取SqlSession對(duì)象 session = factory.openSession(true); //4.獲取DAO的代理對(duì)象 iuSerDao = session.getMapper(IUSerDao.class); } @After//用于在測(cè)試方法之后執(zhí)行 public void destroy() throws IOException { //事務(wù)提交 //session.commit(); //釋放資源 session.close(); in.close(); } /** * 測(cè)試查詢所有 * @throws IOException */ @Test public void testFindAll() throws IOException { //5.執(zhí)行查詢所有方法 List<User> users = iuSerDao.findAll(); } }
沒(méi)有使用主對(duì)象的屬性(詳情)時(shí),只執(zhí)行了主對(duì)象的查詢。
修改測(cè)試方法為
@Test public void testFindAll() throws IOException { //5.執(zhí)行查詢所有方法 List<User> users = iuSerDao.findAll(); System.out.println(users.get(0).getUsername()); }
在執(zhí)行主對(duì)象屬性(詳情)的時(shí)候,執(zhí)行關(guān)聯(lián)對(duì)象:
5. 深度延遲加載
主配置文件SqlMapConfig.xml中設(shè)置lazyLoadingEnabled為true,默認(rèn)為false,并且將aggressiveLazyLoading設(shè)置為false。(aggressiveLazyLoading默認(rèn)值為false (在 3.4.1 及之前的版本中默認(rèn)為 true))
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 配置properties --> <properties resource="jdbcConfig.properties"></properties> <!-- 配置參數(shù) --> <settings> <!-- 開(kāi)啟mybatis支持延遲加載 --> <setting name="lazyLoadingEnabled" value="true"/> <setting name="aggressiveLazyLoading" value="false"/> </settings> <!-- 使用typeAliases配置別名,它只能配置domain中類的別名 --> <typeAliases> <package name="com.siyi.domain"></package> </typeAliases> <!-- 配置環(huán)境 --> <environments default="mysql"> <!-- 配置mysql的環(huán)境 --> <environment id="mysql"> <!-- 配置事務(wù) --> <transactionManager type="JDBC"></transactionManager> <!-- 配置連接池 --> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </dataSource> </environment> </environments> <!-- 映射配置文件 --> <mappers> <mapper resource="com/siyi/dao/IUserDao.xml"/> <mapper resource="com/siyi/dao/IAccountDao.xml"/> </mappers> </configuration>
dao映射配置文件不變
測(cè)試
package com.siyi.test; import com.siyi.dao.IUSerDao; import com.siyi.domain.User; 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.After; import org.junit.Before; import org.junit.Test; import java.io.IOException; import java.io.InputStream; import java.util.List; public class UserTest { private InputStream in; private SqlSession session; private IUSerDao iuSerDao; @Before//用于在測(cè)試方法執(zhí)行之前執(zhí)行 public void init() throws IOException { //1.讀取配置文件生成字節(jié)輸入流 in = Resources.getResourceAsStream("SqlMapConfig.xml"); //2.獲取SqlSessionFactory對(duì)象 SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(in); //3.獲取SqlSession對(duì)象 session = factory.openSession(true); //4.獲取DAO的代理對(duì)象 iuSerDao = session.getMapper(IUSerDao.class); } @After//用于在測(cè)試方法之后執(zhí)行 public void destroy() throws IOException { //事務(wù)提交 //session.commit(); //釋放資源 session.close(); in.close(); } /** * 測(cè)試查詢所有 * @throws IOException */ @Test public void testFindAll() throws IOException { //5.執(zhí)行查詢所有方法 List<User> users = iuSerDao.findAll(); System.out.println(users.get(0).getUsername()); } }
沒(méi)有用到關(guān)聯(lián)對(duì)象時(shí),只查詢主對(duì)象一次
修改測(cè)試方法
@Test public void testFindAll() throws IOException { //5.執(zhí)行查詢所有方法 List<User> users = iuSerDao.findAll(); System.out.println(users.get(0).getAccounts()); }
用到關(guān)聯(lián)對(duì)象數(shù)據(jù)的時(shí)候執(zhí)行關(guān)聯(lián)對(duì)象的查詢。
6. 延遲加載總結(jié)
延遲加載一般就是按需加載,在需要查詢的時(shí)候再去查詢,使用延遲加載可以避免表連接查詢,表連接查詢比單表查詢的效率低,但是它需要多次與數(shù)據(jù)庫(kù)進(jìn)行交互,所以延遲加載使用需謹(jǐn)慎。
關(guān)于延遲加載有兩個(gè)重要的設(shè)置:lazyLoadingEnabled表示延遲加載是否開(kāi)啟,如果設(shè)置為true表示開(kāi)啟,此時(shí)還需要設(shè)置aggressiveLazyLoading為false,才能做到按需加載,如果aggressiveLazyLoading設(shè)置為true則按需加載關(guān)閉,此時(shí)只要加載了某個(gè)屬性就會(huì)將所有屬性都加載。
lazyLoadingEnabled的默認(rèn)值為false
aggressiveLazyLoading的默認(rèn)值為true
注意: 延遲加載的應(yīng)用要求,關(guān)聯(lián)對(duì)象的查詢與主加載對(duì)象的查詢必須是分別進(jìn)行的 select 語(yǔ)句,不能是使用多表連接所進(jìn)行的select查詢。
到此這篇關(guān)于一文看懂Mybatis中的延遲加載的文章就介紹到這了,更多相關(guān)Mybatis延遲加載內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Springboot創(chuàng)建子父工程過(guò)程圖解
這篇文章主要介紹了Springboot創(chuàng)建子父工程過(guò)程圖解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02java后臺(tái)本地文件轉(zhuǎn)為MultipartFile類型的實(shí)現(xiàn)方式
在Java后臺(tái)將本地文件轉(zhuǎn)換為MultipartFile類型,可以通過(guò)使用FileItemFactory創(chuàng)建FileItem,然后使用CommonsMultipartFile類構(gòu)造一個(gè)MultipartFile對(duì)象,將本地文件流轉(zhuǎn)換為MultipartFile,getMultipartFiles()和getMultipartFiles()方法2025-02-02WebDriver中實(shí)現(xiàn)對(duì)特定的Web區(qū)域截圖方法
這篇文章主要介紹了WebDriver中實(shí)現(xiàn)對(duì)特定的Web區(qū)域截圖方法,本文直接給出實(shí)現(xiàn)代碼,需要的朋友可以參考下2015-06-06mybatis collection關(guān)聯(lián)查詢多個(gè)參數(shù)方式
在使用MyBatis進(jìn)行關(guān)聯(lián)查詢時(shí),往往需要根據(jù)多個(gè)參數(shù)進(jìn)行查詢,例如,使用evtId和businessType作為查詢條件,同時(shí)在resultMap中配置id和businessType1作為結(jié)果映射,這種情況下,可以通過(guò)<sql>標(biāo)簽定義參數(shù)模板,或者使用@Param注解指定參數(shù)名稱2024-10-10Open-Feign整合hystrix降級(jí)熔斷實(shí)戰(zhàn)記錄
這篇文章主要介紹了Open-Feign整合hystrix降級(jí)熔斷實(shí)戰(zhàn)記錄,本文通過(guò)實(shí)例圖文相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-09-09詳解SpringMVC @RequestBody接收J(rèn)son對(duì)象字符串
這篇文章主要介紹了詳解SpringMVC @RequestBody接收J(rèn)son對(duì)象字符串,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-01-01