深入理解什么是Mybatis懶加載(延遲加載)
mybatis懶加載
mybatis的懶加載,也稱(chēng)為延遲加載,是指在進(jìn)行關(guān)聯(lián)查詢(xún)的時(shí)候,按照設(shè)置延遲規(guī)則推遲對(duì)關(guān)聯(lián)對(duì)象的select查詢(xún),延遲加載可以有效的減少數(shù)據(jù)庫(kù)壓力。
延遲加載只對(duì)關(guān)聯(lián)對(duì)象有延遲設(shè)置,主加載對(duì)象都是直接執(zhí)行查詢(xún)語(yǔ)句的
關(guān)聯(lián)對(duì)象加載類(lèi)型
mybatis的關(guān)聯(lián)對(duì)象的查詢(xún)select語(yǔ)句的執(zhí)行時(shí)機(jī),可以分為3類(lèi),直接加載,侵入式加載與深度延遲加載。
1.直接加載
執(zhí)行完主加載對(duì)象的select語(yǔ)句,馬上就會(huì)執(zhí)行關(guān)聯(lián)對(duì)象的select語(yǔ)句。
2.侵入式延遲加載
執(zhí)行對(duì)主加載對(duì)象的查詢(xún)時(shí),不會(huì)執(zhí)行關(guān)聯(lián)對(duì)象的查詢(xún),但是當(dāng)訪(fǎng)問(wèn)主加載對(duì)象的詳情時(shí),就會(huì)馬上執(zhí)行關(guān)聯(lián)對(duì)象的select查詢(xún),也就是說(shuō)關(guān)聯(lián)對(duì)象的查詢(xún)執(zhí)行,侵入到了豬價(jià)在對(duì)象的詳情訪(fǎng)問(wèn)中,可以理解為,將關(guān)聯(lián)對(duì)象的詳情侵入到主加載對(duì)象的詳情中,作為它的一部分出現(xiàn)了。
3.深度延遲加載
執(zhí)行對(duì)主加載對(duì)象的查詢(xún)的時(shí)候,不會(huì)執(zhí)行對(duì)關(guān)聯(lián)對(duì)象的查詢(xún),訪(fǎng)問(wèn)主加載對(duì)象的詳情的時(shí)候,也不會(huì)執(zhí)行關(guān)聯(lián)對(duì)象的select查詢(xún),只有當(dāng)真正的訪(fǎng)問(wèn)關(guān)聯(lián)對(duì)象的詳情的時(shí)候,才會(huì)執(zhí)行對(duì)關(guān)聯(lián)對(duì)象的select查詢(xún)。
注意:延遲加載的最基本要求,關(guān)聯(lián)對(duì)象的查詢(xún)與主加載對(duì)象的查詢(xún)必須是分別放在兩個(gè)語(yǔ)句中的,不能使用多表連接查詢(xún),因?yàn)槎啾磉B接查詢(xún)相當(dāng)于把多張表連接成一張表的查詢(xún),無(wú)法做到分開(kāi)查詢(xún),會(huì)一次性將表的內(nèi)容查詢(xún)出來(lái)。 延遲加載,可以應(yīng)用到一對(duì)多,一對(duì)一,多對(duì)一,多對(duì)多的關(guān)聯(lián)查詢(xún)中。
舉個(gè)例子:我們只用上一個(gè)demo,查詢(xún)minister與country之間的關(guān)系,數(shù)據(jù)庫(kù)如下:
#創(chuàng)建數(shù)據(jù)庫(kù)
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');
與之對(duì)應(yīng)的實(shí)體類(lèi):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ù)庫(kù)文件 -->
<properties resource="jdbc_mysql.properties">
</properties>
<settings>
<setting name="lazyLoadingEnabled" value="false"/>
<!--<setting name="aggressiveLazyLoading" value="false"/>-->
</settings>
<!-- 別名,對(duì)數(shù)據(jù)對(duì)象操作全名太長(zhǎng),需要使用別名 -->
<typeAliases>
<!--<typeAlias type="bean.Student" alias="Student"/>-->
<!--直接使用類(lèi)名即可,對(duì)于整個(gè)包的路徑配置(別名),簡(jiǎn)單快捷 -->
<package name="beans"/>
</typeAliases>
<!-- 配置運(yùn)行環(huán)境 -->
<!-- default 表示默認(rèn)使用哪一個(gè)環(huán)境,可以配置多個(gè),比如開(kāi)發(fā)時(shí)的測(cè)試環(huán)境,上線(xià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>
<!-- 注冊(cè)映射文件 -->
<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 能解決字段和屬性不一樣的問(wèn)題 -->
<!-- 以后用得比較多 ,是因?yàn)榭梢允褂醚舆t加載-->
<!-- 嵌套查詢(xún) -->
<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>
與之對(duì)應(yīng)的sql接口:
public interface ICountryDao {
Country selectCountryById(int cid);
}
使用到的工具類(lèi):
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;
}
}
直接加載查詢(xún)
關(guān)于懶加載的配置,我們只需要在mybatis.xml文件里面使用就可以了,懶加載有一個(gè)總開(kāi)關(guān),lazyloadingEnabled,只要置為false就可以將延遲加載關(guān)掉,那就是直接加載查詢(xún)了。配置在與之間。
<properties resource="jdbc_mysql.properties">
</properties>
<settings>
<setting name="lazyLoadingEnabled" value="flase"/>
</settings>
<!-- 別名,對(duì)數(shù)據(jù)對(duì)象操作全名太長(zhǎng),需要使用別名 -->
<typeAliases>
<!--<typeAlias type="bean.Student" alias="Student"/>-->
<!--直接使用類(lèi)名即可,對(duì)于整個(gè)包的路徑配置(別名),簡(jiǎn)單快捷 -->
<package name="bean"/>
</typeAliases>
當(dāng)單元測(cè)試是直接?xùn)薱ountry對(duì)象的時(shí)候:
@Test
public void TestselectCountryById(){
Country country=dao.selectCountryById(1);
}
結(jié)果是,我們可以看到兩條sql,除了查詢(xún)country之外,連同minister關(guān)聯(lián)對(duì)象也一起查詢(xún)了,這就是直接加載,簡(jiǎn)單粗暴,不管是否使用,都會(huì)先將關(guān)聯(lián)查詢(xú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
侵入式延遲加載
需要將延遲加載開(kāi)關(guān)開(kāi)啟(true),同時(shí)也需要將侵入式加載開(kāi)關(guān)開(kāi)啟(true)
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressivelazyLoading" value="true"/>
</settings>
1.當(dāng)我們只查詢(xún)country的時(shí)候,只會(huì)執(zhí)行country的查詢(xún),不會(huì)執(zhí)行關(guān)聯(lián)查詢(xú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)我們查詢(xún)country的屬性,但是不是minister屬性的時(shí)候:
@Test
public void TestselectCountryById(){
Country country=dao.selectCountryById(1);
System.out.println(country.getCid());
}
結(jié)果如下,會(huì)加載到關(guān)聯(lián)對(duì)象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
深度延遲加載
需要將延遲加載開(kāi)關(guān)開(kāi)啟(true),同時(shí)需要將侵入式加載開(kāi)關(guān)關(guān)閉(false)
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressivelazyLoading" value="false"/>
</settings>
1.當(dāng)我們只查詢(xún)出country的時(shí)候,只會(huì)查詢(xún)country,而不會(huì)查詢(xún)minister: 單元測(cè)試代碼:
@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)我們?cè)L問(wèn)country的屬性的時(shí)候,也不會(huì)加載關(guān)聯(lián)查詢(xú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)我們查詢(xún)country屬性minister的時(shí)候:
@Test
public void TestselectCountryById(){
Country country=dao.selectCountryById(1);
System.out.println(country.getMinisters());
}
我們可以看到結(jié)果,執(zhí)行了minister的查詢(xún):
[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]]
來(lái)個(gè)表格~
| 加載方式 | lazyLoadingEnabled | aggressiveLazyLoading |
| 直接加載 | 必須是false,默認(rèn)是false | 不管是什么,只要lazyLoadingEnabled是false就是直接加載 |
| 侵入式延遲加載 | 必須是true | 必須是true |
| 深度延遲加載 | 必須是true | 必須是false,默認(rèn)是false |
到此這篇關(guān)于深入理解什么是Mybatis懶加載(延遲加載)的文章就介紹到這了,更多相關(guān)Mybatis懶加載(延遲加載)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android 資源 id詳解及的動(dòng)態(tài)獲取
這篇文章主要介紹了Android 資源 id詳解及的動(dòng)態(tài)獲取的相關(guān)資料,需要的朋友可以參考下2016-12-12
如何在Spring Boot 項(xiàng)目中自定義 Validation 注解
本文詳解SpringBoot自定義Validation注解實(shí)現(xiàn)流程,包括定義注解、編寫(xiě)校驗(yàn)邏輯、應(yīng)用注解及異常處理,支持多地區(qū)手機(jī)號(hào)格式校驗(yàn)和復(fù)雜業(yè)務(wù)規(guī)則,提升數(shù)據(jù)合法性校驗(yàn)?zāi)芰?適用于微服務(wù)架構(gòu)參數(shù)校驗(yàn)實(shí)踐,感興趣的朋友一起看看吧2025-07-07
springboot項(xiàng)目以jar包運(yùn)行的操作方法
公司一個(gè)springboot項(xiàng)目本來(lái)是打war包的,突然要改為打jar包,不知所措了,糾結(jié)該如何操作呢,折騰半天終于搞定了,下面把解決方案分享給大家,對(duì)springboot打jar包方式感興趣的朋友一起看看吧2021-06-06

