Mybatis 中一對一项栏,一對多亡资,多對多關(guān)系的配置及實現(xiàn),可以實現(xiàn)對象的關(guān)聯(lián)查詢板驳。實際開發(fā)過程中很多時候我們并不需要總是在加載用戶信息時就一定要加載他的賬戶信息。此時就是我們所說的延遲加載碍拆。
1. 何為延遲加載
延遲加載:
就是在需要用到數(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ù)查詢時庭呜,因為查詢工作也要消耗時間滑进,所以可能造成用戶等待時間變長摹迷,造成用戶體驗下降。
延遲加載:在真正使用數(shù)據(jù)時才發(fā)起查詢郊供,不用的時候不查詢峡碉。按需加載(懶加載)
立即加載:不管用不用,只要一調(diào)用方法驮审,馬上發(fā)起查詢鲫寄。
在對應(yīng)的四種表關(guān)系中:一對多,多對一疯淫,一對一地来,多對多
1)一對多,多對多:通常情況下我們都是采用延遲加載熙掺。
2)多對一未斑,一對一:通常情況下我們都是采用立即加載。
2. 實現(xiàn)需求
需求:
查詢賬戶(Account)信息并且關(guān)聯(lián)查詢用戶(User)信息币绩。如果先查詢賬戶(Account)信息即可滿足要求蜡秽,當(dāng)我們需要查詢用戶(User)信息時再查詢用戶(User)信息。把對用戶(User)信息的按需去查詢就是延遲加
載缆镣。
mybatis實現(xiàn)多表操作時芽突,我們使用了resultMap來實現(xiàn)一對一,一對多董瞻,多對多關(guān)系的操作寞蚌。主要是通過 association、collection 實現(xiàn)一對一及一對多映射钠糊。association挟秤、collection 具備延遲加載功能。
3. 使用 assocation實現(xiàn)延遲加載
需求:查詢賬戶信息同時查詢用戶信息抄伍。
3.1 創(chuàng)建工程
這里可以用之前的一對多的工程模板為例艘刚,修改如下
3.2 賬戶的持久層 DAO
package com.neuedu.dao;
import com.neuedu.domain.Account;
import java.util.List;
public interface AccountDao {
/**
* 查詢所有賬戶,同時還要獲取到當(dāng)前賬戶的所屬用戶信息
* @return
*/
List<Account> findAll();
}
3.3 用戶的持久層 映射文件
UserDao.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.neuedu.dao.UserDao">
<!-- 定義User的resultMap-->
<resultMap id="userAccountMap" type="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集合的映射 -->
<collection property="accounts" ofType="account">
<id column="aid" property="id"></id>
<result column="uid" property="uid"></result>
<result column="money" property="money"></result>
</collection>
</resultMap>
<!-- 查詢所有 -->
<select id="findAll" resultMap="userAccountMap">
select * from user
</select>
<!-- 根據(jù)id查詢用戶 -->
<select id="findById" parameterType="INT" resultType="user">
select * from user where id = #{uid}
</select>
</mapper>
3.4 賬戶的持久層 接口和 映射文件
AccountDao.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.neuedu.dao.AccountDao">
<!-- 定義封裝account和user的resultMap -->
<resultMap id="accountUserMap" type="account">
<id property="id" column="id"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!-- 一對一的關(guān)系映射:配置封裝user的內(nèi)容
select屬性指定的內(nèi)容:查詢用戶的唯一標(biāo)識:
column屬性指定的內(nèi)容:用戶根據(jù)id查詢時逝慧,所需要的參數(shù)的值
-->
<association property="user" column="uid" javaType="user" select="com.neuedu.dao.UserDao.findById"></association>
</resultMap>
<!-- 查詢所有 -->
<select id="findAll" resultMap="accountUserMap">
select * from account
</select>
<!-- 根據(jù)用戶id查詢賬戶列表 -->
<select id="findAccountByUid" resultType="account">
select * from account where uid = #{uid}
</select>
</mapper>
3.5 測試類
package com.neuedu.test;
import com.neuedu.dao.AccountDao;
import com.neuedu.domain.Account;
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.InputStream;
import java.util.List;
public class AccountTest {
private InputStream in;
private SqlSession sqlSession;
private AccountDao accountDao;
@Before//用于在測試方法執(zhí)行之前執(zhí)行
public void init()throws Exception{
//1.讀取配置文件昔脯,生成字節(jié)輸入流
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.獲取SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//3.獲取SqlSession對象
sqlSession = factory.openSession(true);
//4.獲取dao的代理對象
accountDao = sqlSession.getMapper(AccountDao.class);
}
@After//用于在測試方法執(zhí)行之后執(zhí)行
public void destroy()throws Exception{
//提交事務(wù)
// sqlSession.commit();
//6.釋放資源
sqlSession.close();
in.close();
}
/**
* 測試查詢所有
*/
@Test
public void testFindAll(){
List<Account> accounts = accountDao.findAll();
for(Account account : accounts){
System.out.println("--------每個account的信息------------");
System.out.println(account);
System.out.println(account.getUser());
}
}
}
3.6 開啟 Mybatis 的延遲加載策略
未開啟延遲加載
<?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>
<!--開啟Mybatis支持延遲加載-->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"></setting>
</settings>
<!--使用typeAliases配置別名啄糙,它只能配置domain中類的別名 -->
<typeAliases>
<package name="com.neuedu.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>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</dataSource>
</environment>
</environments>
<!-- 配置映射文件的位置 -->
<mappers>
<package name="com.neuedu.dao"></package>
</mappers>
</configuration>
4. 使用 Collection 實現(xiàn)延遲加載
同樣我們也可以在一對多關(guān)系配置的<collection>結(jié)點中配置延遲加載策略笛臣。
<collection>結(jié)點中也有 select 屬性,column 屬性隧饼。
需求:
完成加載用戶對象時沈堡,查詢該用戶所擁有的賬戶信息。
4.1 在 在 User 實體類中加入 List<Account> 屬性
public class User implements Serializable {
private Integer id;
private String username;
private String address;
private String sex;
private Date birthday;
//一對多關(guān)系映射:主表實體應(yīng)該包含從表實體的集合引用
private List<Account> accounts;
public List<Account> getAccounts() {
return accounts;
}
public void setAccounts(List<Account> accounts) {
this.accounts = accounts;
}
...
}
4.2 編寫用戶和賬戶持久層接口的方法
public interface AccountDao {
/**
* 根據(jù)用戶id查詢賬戶信息
* @param uid
* @return
*/
List<Account> findAccountByUid(Integer uid);
}
4.3 編寫用戶持久層映射 配置
UserDao.xml
<resultMap type="user" id="userMap">
<id column="id" property="id"></id>
<result column="username" property="username"/>
<result column="address" property="address"/>
<result column="sex" property="sex"/>
<result column="birthday" property="birthday"/>
<!-- collection 是用于建立一對多中集合屬性的對應(yīng)關(guān)系
ofType 用于指定集合元素的數(shù)據(jù)類型
select 是用于指定查詢賬戶的唯一標(biāo)識(賬戶的 dao 全限定類名加上方法名稱)
column 是用于指定使用哪個字段的值作為條件查詢
-->
<collection property="accounts" ofType="account"
select="com.neuedu.dao.AccountDao.findByUid"
column="id">
</collection>
</resultMap>
<!-- 配置查詢所有操作 -->
<select id="findAll" resultMap="userMap">
select * from user
</select>
<collection> 標(biāo)簽 :
主要用于加載關(guān)聯(lián)的集合對象
select 屬性 :用于指定查詢 account 列表的 sql 語句燕雁,所以填寫的是該 sql 映射的 id
column 屬性 :用于指定 select 屬性的 sql 語句的參數(shù)來源诞丽,上面的參數(shù)來自于 user 的 id 列鲸拥,所以就寫成 id 這一個字段名了
4.4 編寫賬戶持久層映射配置
<!-- 根據(jù)用戶 id 查詢賬戶信息 -->
<select id="findByUid" resultType="account" parameterType="int">
select * from account where uid = #{uid}
</select>
4.5 測試只加載用戶信息
我們發(fā)現(xiàn)并沒有加載 Account 賬戶信息。