深入理解什么是Mybatis懶加載(延遲加載)
mybatis懶加載
mybatis的懶加載,也稱為延遲加載,是指在進(jìn)行關(guān)聯(lián)查詢的時(shí)候,按照設(shè)置延遲規(guī)則推遲對關(guān)聯(lián)對象的select查詢,延遲加載可以有效的減少數(shù)據(jù)庫壓力。
延遲加載只對關(guān)聯(lián)對象有延遲設(shè)置,主加載對象都是直接執(zhí)行查詢語句的
關(guān)聯(lián)對象加載類型
mybatis的關(guān)聯(lián)對象的查詢select語句的執(zhí)行時(shí)機(jī),可以分為3類,直接加載,侵入式加載與深度延遲加載。
1.直接加載
執(zhí)行完主加載對象的select語句,馬上就會(huì)執(zhí)行關(guān)聯(lián)對象的select語句。
2.侵入式延遲加載
執(zhí)行對主加載對象的查詢時(shí),不會(huì)執(zhí)行關(guān)聯(lián)對象的查詢,但是當(dāng)訪問主加載對象的詳情時(shí),就會(huì)馬上執(zhí)行關(guān)聯(lián)對象的select查詢,也就是說關(guān)聯(lián)對象的查詢執(zhí)行,侵入到了豬價(jià)在對象的詳情訪問中,可以理解為,將關(guān)聯(lián)對象的詳情侵入到主加載對象的詳情中,作為它的一部分出現(xiàn)了。
3.深度延遲加載
執(zhí)行對主加載對象的查詢的時(shí)候,不會(huì)執(zhí)行對關(guān)聯(lián)對象的查詢,訪問主加載對象的詳情的時(shí)候,也不會(huì)執(zhí)行關(guān)聯(lián)對象的select查詢,只有當(dāng)真正的訪問關(guān)聯(lián)對象的詳情的時(shí)候,才會(huì)執(zhí)行對關(guān)聯(lián)對象的select查詢。
注意:延遲加載的最基本要求,關(guān)聯(lián)對象的查詢與主加載對象的查詢必須是分別放在兩個(gè)語句中的,不能使用多表連接查詢,因?yàn)槎啾磉B接查詢相當(dāng)于把多張表連接成一張表的查詢,無法做到分開查詢,會(huì)一次性將表的內(nèi)容查詢出來。 延遲加載,可以應(yīng)用到一對多,一對一,多對一,多對多的關(guān)聯(lián)查詢中。
舉個(gè)例子:我們只用上一個(gè)demo,查詢minister與country之間的關(guān)系,數(shù)據(jù)庫如下:
#創(chuàng)建數(shù)據(jù)庫 CREATE DATABASE `test` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; #創(chuàng)建數(shù)據(jù)表 CREATE TABLE `test`.`student` ( `sid` INT(10) NOT NULL AUTO_INCREMENT ,`sname` VARCHAR(20) NOT NULL ,PRIMARY KEY(`sid`)) ENGINE = MyISAM; CREATE TABLE `test`.`course` ( `cid` INT(10) NOT NULL AUTO_INCREMENT ,`cname` VARCHAR(20) NOT NULL ,PRIMARY KEY(`cid`)) ENGINE = MyISAM; CREATE TABLE `test`.`middle` ( `id` INT(10) NOT NULL AUTO_INCREMENT ,`studentId` INT(10) NOT NULL ,`courseId` INT(10) NOT NULL ,PRIMARY KEY(`id`)) ENGINE = MyISAM; #初始化數(shù)據(jù)表 INSERT INTO `course` (`cid`, `cname`) VALUES ('1', 'JAVA') ; INSERT INTO `course` (`cid`, `cname`) VALUES ('2', 'C++') ; INSERT INTO `course` (`cid`, `cname`) VALUES ('3', 'JS') ; INSERT INTO `student` (`sid`, `sname`) VALUES ('1', 'Jam') ; INSERT INTO `student` (`sid`, `sname`) VALUES ('2', 'Lina') ; INSERT INTO `middle` (`id`, `studentId`, `courseId`) VALUES ('1', '1', '1'); INSERT INTO `middle` (`id`, `studentId`, `courseId`) VALUES ('2', '1', '2'); INSERT INTO `middle` (`id`, `studentId`, `courseId`) VALUES ('3', '2', '1'); INSERT INTO `middle` (`id`, `studentId`, `courseId`) VALUES ('4', '2', '3');
與之對應(yīng)的實(shí)體類:Country.class
public class Country { private Integer cid; private String cname; private Set<Minister> ministers; public Integer getCid() { return cid; } public void setCid(Integer cid) { this.cid = cid; } public String getName() { return cname; } public void setName(String cname) { this.cname = cname; } public Set<Minister> getMinisters() { return ministers; } public void setMinisters(Set<Minister> ministers) { this.ministers = ministers; } @Override public String toString() { return "Country [cid=" + cid + ", cname=" + cname + ", ministers=" + ministers + "]"; } }
Minister.class
public class Minister { private Integer mid; private String mname; @Override public String toString() { return "Minister [mid=" + mid + ", mname=" + mname + "]"; } public Integer getMid() { return mid; } public void setMid(Integer mid) { this.mid = mid; } public String getMname() { return mname; } public void setMname(String mname) { this.mname = mname; } }
主配置文件mybatis.xml:
<?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> <!-- 配置數(shù)據(jù)庫文件 --> <properties resource="jdbc_mysql.properties"> </properties> <settings> <setting name="lazyLoadingEnabled" value="false"/> <!--<setting name="aggressiveLazyLoading" value="false"/>--> </settings> <!-- 別名,對數(shù)據(jù)對象操作全名太長,需要使用別名 --> <typeAliases> <!--<typeAlias type="bean.Student" alias="Student"/>--> <!--直接使用類名即可,對于整個(gè)包的路徑配置(別名),簡單快捷 --> <package name="beans"/> </typeAliases> <!-- 配置運(yùn)行環(huán)境 --> <!-- default 表示默認(rèn)使用哪一個(gè)環(huán)境,可以配置多個(gè),比如開發(fā)時(shí)的測試環(huán)境,上線后的正式環(huán)境等 --> <environments default="mysqlEM"> <environment id="mysqlEM"> <transactionManager type="JDBC"> </transactionManager> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.user}"/> <property name="password" value="${jdbc.password}"/> </dataSource> </environment> </environments> <!-- 注冊映射文件 --> <mappers> <mapper resource="mapper/mapper.xml"/> </mappers> </configuration>
mapper.xml文件:
<?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="dao.ICountryDao"> <!-- resultMap 能解決字段和屬性不一樣的問題 --> <!-- 以后用得比較多 ,是因?yàn)榭梢允褂醚舆t加載--> <!-- 嵌套查詢 --> <select id="selectMinisterByCountry" resultType="Minister"> select mid,mname from minister where countryId=#{ooo} </select> <resultMap type="Country" id="countryMapper"> <id column="cid" property="cid"/> <result column="cname" property="cname"/> <!-- country中有一個(gè)成員變量是ministers,它的泛型是Minister --> <collection property="ministers" ofType="Minister" select="selectMinisterByCountry" column="cid"> </collection> </resultMap> <select id="selectCountryById" resultMap="countryMapper"> select cid,cname from country where cid=#{cid} </select> </mapper>
與之對應(yīng)的sql接口:
public interface ICountryDao { Country selectCountryById(int cid); }
使用到的工具類:
public class MyBatisUtils { private static SqlSessionFactory sqlSessionFactory; public static SqlSession getSqlSession() { InputStream is; try { is = Resources.getResourceAsStream("mybatis.xml"); if (sqlSessionFactory == null) { sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); } return sqlSessionFactory.openSession(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } }
直接加載查詢
關(guān)于懶加載的配置,我們只需要在mybatis.xml文件里面使用就可以了,懶加載有一個(gè)總開關(guān),lazyloadingEnabled,只要置為false就可以將延遲加載關(guān)掉,那就是直接加載查詢了。配置在與之間。
<properties resource="jdbc_mysql.properties"> </properties> <settings> <setting name="lazyLoadingEnabled" value="flase"/> </settings> <!-- 別名,對數(shù)據(jù)對象操作全名太長,需要使用別名 --> <typeAliases> <!--<typeAlias type="bean.Student" alias="Student"/>--> <!--直接使用類名即可,對于整個(gè)包的路徑配置(別名),簡單快捷 --> <package name="bean"/> </typeAliases>
當(dāng)單元測試是直接?xùn)薱ountry對象的時(shí)候:
@Test public void TestselectCountryById(){ Country country=dao.selectCountryById(1); }
結(jié)果是,我們可以看到兩條sql,除了查詢country之外,連同minister關(guān)聯(lián)對象也一起查詢了,這就是直接加載,簡單粗暴,不管是否使用,都會(huì)先將關(guān)聯(lián)查詢加載:
[service] 2018-07-17 09:59:00,796 - dao.ICountryDao.selectCountryById -491 [main] DEBUG dao.ICountryDao.selectCountryById - ==> Preparing: select cid,cname from country where cid=?
[service] 2018-07-17 09:59:00,823 - dao.ICountryDao.selectCountryById -518 [main] DEBUG dao.ICountryDao.selectCountryById - ==> Parameters: 1(Integer)
[service] 2018-07-17 09:59:00,838 - dao.ICountryDao.selectMinisterByCountry -533 [main] DEBUG dao.ICountryDao.selectMinisterByCountry - ====> Preparing: select mid,mname from minister where countryId=?
[service] 2018-07-17 09:59:00,838 - dao.ICountryDao.selectMinisterByCountry -533 [main] DEBUG dao.ICountryDao.selectMinisterByCountry - ====> Parameters: 1(Integer)
[service] 2018-07-17 09:59:00,849 - dao.ICountryDao.selectMinisterByCountry -544 [main] DEBUG dao.ICountryDao.selectMinisterByCountry - <==== Total: 2
[service] 2018-07-17 09:59:00,850 - dao.ICountryDao.selectCountryById -545 [main] DEBUG dao.ICountryDao.selectCountryById - <== Total: 1
侵入式延遲加載
需要將延遲加載開關(guān)開啟(true),同時(shí)也需要將侵入式加載開關(guān)開啟(true)
<settings> <setting name="lazyLoadingEnabled" value="true"/> <setting name="aggressivelazyLoading" value="true"/> </settings>
1.當(dāng)我們只查詢country的時(shí)候,只會(huì)執(zhí)行country的查詢,不會(huì)執(zhí)行關(guān)聯(lián)查詢minister:
@Test public void TestselectCountryById(){ Country country=dao.selectCountryById(1); }
結(jié)果如下,只有一條sql:
[service] 2018-07-17 14:30:55,471 - dao.ICountryDao.selectCountryById -902 [main] DEBUG dao.ICountryDao.selectCountryById - ==> Preparing: select cid,cname from country where cid=?
[service] 2018-07-17 14:30:55,494 - dao.ICountryDao.selectCountryById -925 [main] DEBUG dao.ICountryDao.selectCountryById - ==> Parameters: 1(Integer)
[service] 2018-07-17 14:30:55,590 - dao.ICountryDao.selectCountryById -1021 [main] DEBUG dao.ICountryDao.selectCountryById - <== Total: 1
當(dāng)我們查詢country的屬性,但是不是minister屬性的時(shí)候:
@Test public void TestselectCountryById(){ Country country=dao.selectCountryById(1); System.out.println(country.getCid()); }
結(jié)果如下,會(huì)加載到關(guān)聯(lián)對象minister,這就是侵入式延遲加載:
[service] 2018-07-17 14:32:37,959 - dao.ICountryDao.selectCountryById -724 [main] DEBUG dao.ICountryDao.selectCountryById - ==> Preparing: select cid,cname from country where cid=?
[service] 2018-07-17 14:32:37,979 - dao.ICountryDao.selectCountryById -744 [main] DEBUG dao.ICountryDao.selectCountryById - ==> Parameters: 1(Integer)
[service] 2018-07-17 14:32:38,170 - dao.ICountryDao.selectCountryById -935 [main] DEBUG dao.ICountryDao.selectCountryById - <== Total: 1
[service] 2018-07-17 14:32:38,171 - dao.ICountryDao.selectMinisterByCountry -936 [main] DEBUG dao.ICountryDao.selectMinisterByCountry - ==> Preparing: select mid,mname from minister where countryId=?
[service] 2018-07-17 14:32:38,171 - dao.ICountryDao.selectMinisterByCountry -936 [main] DEBUG dao.ICountryDao.selectMinisterByCountry - ==> Parameters: 1(Integer)
[service] 2018-07-17 14:32:38,173 - dao.ICountryDao.selectMinisterByCountry -938 [main] DEBUG dao.ICountryDao.selectMinisterByCountry - <== Total: 2
深度延遲加載
需要將延遲加載開關(guān)開啟(true),同時(shí)需要將侵入式加載開關(guān)關(guān)閉(false)
<settings> <setting name="lazyLoadingEnabled" value="true"/> <setting name="aggressivelazyLoading" value="false"/> </settings>
1.當(dāng)我們只查詢出country的時(shí)候,只會(huì)查詢country,而不會(huì)查詢minister: 單元測試代碼:
@Test public void TestselectCountryById(){ Country country=dao.selectCountryById(1); }
[service] 2018-07-17 14:20:38,608 - dao.ICountryDao.selectCountryById -1271 [main] DEBUG dao.ICountryDao.selectCountryById - ==> Preparing: select cid,cname from country where cid=?
[service] 2018-07-17 14:20:38,631 - dao.ICountryDao.selectCountryById -1294 [main] DEBUG dao.ICountryDao.selectCountryById - ==> Parameters: 1(Integer)
[service] 2018-07-17 14:20:38,980 - dao.ICountryDao.selectCountryById -1643 [main] DEBUG dao.ICountryDao.selectCountryById - <== Total: 1
2.當(dāng)我們訪問country的屬性的時(shí)候,也不會(huì)加載關(guān)聯(lián)查詢的minister:
@Test public void TestselectCountryById(){ Country country=dao.selectCountryById(1); System.out.println(country.getCid()); }
結(jié)果同樣是:
[service] 2018-07-17 14:24:03,004 - org.apache.ibatis.transaction.jdbc.JdbcTransaction -686 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@cb51256]
[service] 2018-07-17 14:24:03,030 - dao.ICountryDao.selectCountryById -712 [main] DEBUG dao.ICountryDao.selectCountryById - ==> Preparing: select cid,cname from country where cid=?
[service] 2018-07-17 14:24:03,078 - dao.ICountryDao.selectCountryById -760 [main] DEBUG dao.ICountryDao.selectCountryById - ==> Parameters: 1(Integer)
[service] 2018-07-17 14:24:03,160 - dao.ICountryDao.selectCountryById -842 [main] DEBUG dao.ICountryDao.selectCountryById - <== Total: 1
3.當(dāng)我們查詢country屬性minister的時(shí)候:
@Test public void TestselectCountryById(){ Country country=dao.selectCountryById(1); System.out.println(country.getMinisters()); }
我們可以看到結(jié)果,執(zhí)行了minister的查詢:
[service] 2018-07-17 14:26:55,913 - dao.ICountryDao.selectCountryById -1540 [main] DEBUG dao.ICountryDao.selectCountryById - ==> Preparing: select cid,cname from country where cid=?
[service] 2018-07-17 14:26:55,943 - dao.ICountryDao.selectCountryById -1570 [main] DEBUG dao.ICountryDao.selectCountryById - ==> Parameters: 1(Integer)
[service] 2018-07-17 14:26:56,161 - dao.ICountryDao.selectCountryById -1788 [main] DEBUG dao.ICountryDao.selectCountryById - <== Total: 1
[service] 2018-07-17 14:26:56,162 - dao.ICountryDao.selectMinisterByCountry -1789 [main] DEBUG dao.ICountryDao.selectMinisterByCountry - ==> Preparing: select mid,mname from minister where countryId=?
[service] 2018-07-17 14:26:56,163 - dao.ICountryDao.selectMinisterByCountry -1790 [main] DEBUG dao.ICountryDao.selectMinisterByCountry - ==> Parameters: 1(Integer)
[service] 2018-07-17 14:26:56,168 - dao.ICountryDao.selectMinisterByCountry -1795 [main] DEBUG dao.ICountryDao.selectMinisterByCountry - <== Total: 2
[Minister [mid=2, mname=bbb], Minister [mid=1, mname=aaa]]
來個(gè)表格~
加載方式 | lazyLoadingEnabled | aggressiveLazyLoading |
直接加載 | 必須是false,默認(rèn)是false | 不管是什么,只要lazyLoadingEnabled是false就是直接加載 |
侵入式延遲加載 | 必須是true | 必須是true |
深度延遲加載 | 必須是true | 必須是false,默認(rèn)是false |
到此這篇關(guān)于深入理解什么是Mybatis懶加載(延遲加載)的文章就介紹到這了,更多相關(guān)Mybatis懶加載(延遲加載)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中ConcurrentHashMap和Hashtable的區(qū)別
ConcurrentHashMap?和?Hashtable?都是用于在Java中實(shí)現(xiàn)線程安全的哈希表數(shù)據(jù)結(jié)構(gòu)的類,但它們有很多區(qū)別,本文就來詳細(xì)的介紹一下,感興趣的可以了解一下2023-10-10tk.mybatis通用插件updateByPrimaryKeySelective無法自動(dòng)更新列的解決辦法
tk.mybatis是一個(gè)很好用的通用插件,本文主要介紹了tk.mybatis通用插件updateByPrimaryKeySelective無法自動(dòng)更新列的解決辦法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12Java中基于maven實(shí)現(xiàn)zxing二維碼功能
這篇文章主要介紹了Java中基于maven實(shí)現(xiàn)zxing二維碼功能,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-02-02通過jxl.jar 讀取、導(dǎo)出excel的實(shí)例代碼
通過jxl.jar 讀取、導(dǎo)出excel的實(shí)例代碼,需要的朋友可以參考一下2013-03-03java中JsonObject與JsonArray轉(zhuǎn)換方法實(shí)例
在項(xiàng)目日常開發(fā)中常常會(huì)遇到JSONArray和JSONObject的轉(zhuǎn)換,很多公司剛?cè)肼毜男∶刃聲?huì)卡在這里,下面這篇文章主要給大家介紹了關(guān)于java中JsonObject與JsonArray轉(zhuǎn)換方法的相關(guān)資料,需要的朋友可以參考下2023-04-04