Mybatis的延遲加載
?一、什么是延遲加載
延遲加載: 就是在需要用到數(shù)據(jù)時才進行加載,不需要用到數(shù)據(jù)時就不加載數(shù)據(jù)。延遲加載也稱懶加載.好處: 先從單表查詢,需要時再從關(guān)聯(lián)表去關(guān)聯(lián)查詢,大大提高數(shù)據(jù)庫性能,因為查詢單表要比關(guān)聯(lián)查詢多張表速度要快。壞處: 因為只有當(dāng)需要用到數(shù)據(jù)時,才會進行數(shù)據(jù)庫查詢,這樣在大批量數(shù)據(jù)查詢時,因為查詢工作也要消耗時間,所以可能造成用戶等待時間變長,造成用戶體驗下降。
二、實現(xiàn)需求
需求: 查詢賬戶(Account)信息并且關(guān)聯(lián)查詢用戶(User)信息。如果先查詢賬戶(Account)信息即可滿足要求,當(dāng)我們需要查詢用戶(User)信息時再查詢用戶(User)信息。把對用戶(User)信息的按需去查詢就是延遲加載?! ssociation、collection 具備延遲加載功能。
三、使用association實現(xiàn)延遲加載
需求:
查詢賬戶信息同時查詢用戶信息。
3.1 賬戶的持久層dao接口
package com.llb.dao;import com.llb.domain.Account;import java.util.List;/** * Ceate By llb on 2019/8/7
*/publicinterface AccountMapper {
? ? /**? ? * 查詢賬戶所對應(yīng)的的用戶
? ? */? ? List findAccountAndUser();
}
3.2 賬戶的持久層映射文件
<?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.llb.dao.AccountMapper">
????<!--定義封裝account和user的resultMap-->
????<resultMap id="accountMap" type="com.llb.domain.Account">
????????<id property="id" column="id"></id>
????????<result property="uid" column="uid"></result>
????????<result property="money" column="money"></result>
????????<!--一對一的關(guān)系映射 JavaType:對應(yīng)的是哪個類 select 指定的內(nèi)容:查詢用戶的唯一標(biāo)識 -->
????????<association property="user" column="uid" javaType="com.llb.domain.User" select="com.llb.dao.UserMapper.findById" ></association> ????</resultMap>
????<select id="findAccountAndUser" resultMap="accountMap"> select * from account </select>
</mapper>
3.3 用戶的持久層接口
package com.llb.dao;import com.llb.domain.User;import java.util.List;/** * 用戶的持久層接口
* Ceate By llb on 2019/8/5
*/publicinterface UserMapper {
? ? /**? ? * 根據(jù)id查詢所有用戶
? ? * @return*/? ? User findById(Integer id);
? ? /**? ? * 查詢出所有用戶,包含賬戶信息
? ? * @return*/? ? List findAccountAndUser();
}
3.4 用戶的持久層映射文件
<?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.llb.dao.UserMapper">? ?
????<!--配置 查詢結(jié)果的列名和實體類的屬性名的對應(yīng)關(guān)系-->? ?
????<resultMap id="userMap" type="com.llb.domain.User">? ? ? ?
????????<id property="id" column="id"></id>? ? ? ?
????????<result property="username" column="username"></result>? ? ? ?
????????<result property="address" column="address"></result>? ? ? ?
????????<result property="sex" column="sex"></result>? ? ? ?
????????<result property="birthday" column="birthday"></result>? ? ? ?
????????<!--配置user對象中accounts集合的映射? ? ? ofType:表示集合的類型-->? ? ? ?
????????<collection property="accounts" ofType="com.llb.domain.Account">? ? ? ? ? ?
????????????<id property="id" column="aid"></id>? ? ? ? ? ?
????????????<result property="uid" column="uid"></result>? ? ? ? ? ?
????????????<result property="money" column="money"></result>? ? ? ?
????????????</collection>? ?????????
????</resultMap>? ? <!--查詢出用戶所對應(yīng)的賬戶-->? ?
<select id="findAccountAndUser" resultMap="userMap">? ? ? ? select * from user left outer join account on user.id = account.uid? ? </select>? ? <!--根據(jù)id查詢用戶-->? ? <select id="findById" resultType="user" parameterType="int">? ? ? ? select * from user where id = #{id}? ? </select></mapper>
3.5 開啟mybatis的延遲加載策略
進入 Mybaits 的官方文檔,找到 settings 的說明信息:

我們需要在 Mybatis 的配置文件 SqlMapConfig.xml 文件中添加延遲加載的配置。
? ? <!--配置參數(shù),延遲加載-->
? ? <settings>
? ? ? ? <!--開啟mybatis支持延遲加載-->
? ? ? ? <setting name="lazyLoadingEnabled" value="true"/>
? ? ? ? <!--不配置也可以:默認為false;允許觸發(fā)方法進行延遲加載,否則立即加載-->
? ? ? ? <setting name="aggressiveLazyLoading" value="false"></setting>
? ? </settings>
3.6 編寫測試只查賬戶信息不查用戶信息
*/publicclass AccountTest {
? ? InputStream in =null;
? ? AccountMapper mapper =null;
? ? SqlSession sqlSession =null;
? ? /**? ? * 在測試方法執(zhí)行前執(zhí)行
? ? * @throws IOException
? ? */? ? @Before
? ? publicvoidinit()throws IOException {
? ? ? ? //1.讀取配置文件,生成字節(jié)流in = Resources.getResourceAsStream("SqlMapConfig.xml");
? ? ? ? //2.獲取sqlSessionFactory對象SqlSessionFactory factory =new SqlSessionFactoryBuilder().build(in);
? ? ? ? //3.獲取sqlSession對象sqlSession = factory.openSession();
? ? ? ? //4.獲取dao的代理對象mapper = sqlSession.getMapper(AccountMapper.class);
? ? }
? ? /**? ? * 測試方法執(zhí)行后執(zhí)行
? ? * @throws IOException
? ? */? ? @After
? ? publicvoiddestory()throws IOException {
? ? ? ? sqlSession.commit();
? ? ? ? //6.釋放資源? ? ? ? sqlSession.close();
? ? ? ? in.close();
? ? }
? ? /**? ? * 查詢出賬戶所對應(yīng)的user
? ? */? ? @Test
? ? publicvoid testFindAccountAndUser(){
? ? ? ? List accountUser = mapper.findAccountAndUser();//? ? ? ? for (Account account: accountUser) {//? ? ? ? ? ? System.out.println(account);//? ? ? ? }? ? }
}
3.7 測試結(jié)果
當(dāng)不進行配置時,立即加載,查詢account所對應(yīng)的user,一起將user查詢出來:

配置后,對account進行查詢放入到list集合中,并沒有涉及到user對象,所以就沒有發(fā)出 SQL 語句查詢賬戶所關(guān)聯(lián)的 User 對象的查詢。:

四、使用collection實現(xiàn)緩存策略
同樣我們也可以在一對多關(guān)系配置的<collection>結(jié)點中配置延遲加載策略。
<collection>結(jié)點中也有 select 屬性,column 屬性。
需求:
????完成加載用戶對象時,查詢該用戶所擁有的賬戶信息。
4.1 在User實體類中加入List<Account>屬性
package com.llb.domain;import java.io.Serializable;
import java.util.Date;import java.util.List;/** * Ceate By llb on 2019/8/5
*/publicclassUserimplements Serializable{
? ? private Integer id;
? ? private String username;
? ? private String address;
? ? private String sex;
? ? private Date birthday;
? ? //一對多關(guān)系。一的方包含多的一方所有對象privateList accounts;
? ? @Override
? ? public String toString() {
? ? ? ? return"User{" +? ? ? ? ? ? ? ? "id=" + id +? ? ? ? ? ? ? ? ", username='" + username + '\'' +? ? ? ? ? ? ? ? ", address='" + address + '\'' +? ? ? ? ? ? ? ? ", sex='" + sex + '\'' +? ? ? ? ? ? ? ? ", birthday=" + birthday +? ? ? ? ? ? ? ? ", accounts=" + accounts +? ? ? ? ? ? ? ? '}';
? ? }
? ? publicList getAccounts() {
? ? ? ? return accounts;
? ? }
? ? publicvoidsetAccounts(List accounts) {
? ? ? ? this.accounts = accounts;
? ? }
? ? public Integer getId() {
? ? ? ? return id;
? ? }
? ? publicvoid setId(Integer id) {
? ? ? ? this.id = id;
? ? }
? ? public String getUsername() {
? ? ? ? return username;
? ? }
? ? publicvoid setUsername(String username) {
? ? ? ? this.username = username;
? ? }
? ? public String getAddress() {
? ? ? ? return address;
? ? }
? ? publicvoid setAddress(String address) {
? ? ? ? this.address = address;
? ? }
? ? public String getSex() {
? ? ? ? return sex;
? ? }
? ? publicvoid setSex(String sex) {
? ? ? ? this.sex = sex;
? ? }
? ? public Date getBirthday() {
? ? ? ? return birthday;
? ? }
? ? publicvoid setBirthday(Date birthday) {
? ? ? ? this.birthday = birthday;
? ? }
}
4.2 編寫用戶接口和配置文件
UserMapper.class:
package com.llb.dao;import com.llb.domain.User;import java.util.List;/** * 用戶的持久層接口
* Ceate By llb on 2019/8/5
*/publicinterface UserMapper {
? ? /**? ? * 根據(jù)id查詢所有用戶
? ? * @return*/? ? User findById(Integer id);
? ? /**? ? * 查詢出所有用戶,包含賬戶信息
? ? * @return*/? ? List findAccountAndUser();
}
UserMapper.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="com.llb.dao.UserMapper">
<!--配置 查詢結(jié)果的列名和實體類的屬性名的對應(yīng)關(guān)系-->
<resultMap id="userMap" type="com.llb.domain.User">
<id property="id" column="id"></id>
<result property="username" column="username">
????</result> <result property="address" column="address">
????</result> <result property="sex" column="sex">
????</result> <result property="birthday" column="birthday">
</result>
<!--配置user對象中accounts集合的映射 ofType:表示集合的類型-->
????<collection property="accounts" ofType="com.llb.domain.Account" select="com.llb.dao.AccountMapper.findAccountById" column="id"> </collection>
</resultMap> <!--查詢出用戶所對應(yīng)的賬戶-->
????<select id="findAccountAndUser" resultMap="userMap">
????????select * from user
????</select>
????<!--根據(jù)id查詢用戶-->
????<select id="findById" resultType="user" parameterType="int">
????????select * from user where id = #{id}
????</select>
</mapper>
4.3 使用測試方法進行測試
publicclass UserTest {
? ? InputStream in =null;
? ? UserMapper mapper =null;
? ? SqlSession sqlSession =null;
? ? /**? ? * 在測試方法執(zhí)行前執(zhí)行
? ? * @throws IOException
? ? */? ? @Before
? ? publicvoidinit()throws IOException {
? ? ? ? //1.讀取配置文件,生成字節(jié)流in = Resources.getResourceAsStream("SqlMapConfig.xml");
? ? ? ? //2.獲取sqlSessionFactory對象SqlSessionFactory factory =new SqlSessionFactoryBuilder().build(in);
? ? ? ? //3.獲取sqlSession對象sqlSession = factory.openSession();
? ? ? ? //4.獲取dao的代理對象mapper = sqlSession.getMapper(UserMapper.class);
? ? }
? ? /**? ? * 測試方法執(zhí)行后執(zhí)行
? ? * @throws IOException
? ? */? ? @After
? ? publicvoiddestory()throws IOException {
? ? ? ? sqlSession.commit();
? ? ? ? //6.釋放資源? ? ? ? sqlSession.close();
? ? ? ? in.close();
? ? }
? ? /**? ? * 查詢出所有用戶所對應(yīng)的賬戶
? ? */? ? @Test
? ? publicvoid findUserAndAccount(){
? ? ? ? List users = mapper.findAccountAndUser();
? ? ? ? }
}
測試結(jié)果:

我們沒有使用Accout,也只對User進行了查詢。
Mybatis緩存
源碼:https://github.com/PopsiCola/SSM-mybatis/tree/association_lazy
歡迎star