在實際開發中,有的數據不需要立即加載,而是需要的時候再去加載,不需要用到的時候則不去加載,這就是延時加載,也稱爲按需加載(懶加載)。
-
利 : 提高數據庫性能 弊 : 需要時候在查詢,存在大批量的數據查詢。
assocation的延時加載
要求:查詢賬戶信息,同時按需加載用戶信息。
- 創建實體類
package com.liang.domain;
import java.io.Serializable;
/**
* 賬戶實體類
*/
public class Account implements Serializable {
private int id;
private int uid;
private Double money;
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", uid=" + uid +
", money=" + money +
'}';
}
}
package com.liang.domain;
import java.util.Date;
/**
* 用戶類
*/
public class User {
private int id;
private String username;
private Date birthday;
private String sex;
private String address;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", birthday=" + birthday +
", sex='" + sex + '\'' +
", address='" + address + '\'' +
'}';
}
}
- 創建持久層接口
package com.liang.dao;
import com.liang.domain.Account;
import java.util.List;
/**
* 賬戶的持久層接口
*/
public interface AccountDao {
/**
* 查詢所有賬戶信息,同時包含其用戶信息
* @return
*/
List<Account> findAll();
}
package com.liang.dao;
public interface UserDao{
/**
* 根據id查詢用戶
* @param id
* @return
*/
User findById(int id);
}
- 編寫持久層映射文件
<resultMap id="accountMap" type="com.liang.domain.Account">
<id property="id" column="id"></id>
<result column="uid" property="uid"></result>
<result column="money" property="money"></result>
<!--建立Account類中user屬性對應的數據庫表
column: 數據庫中的列名,或者是列的別名。一般情況下,是我們傳遞給select映射的參數
select: 用於加載複雜類型屬性的映射語句的 ID,它會從 column 屬性指定的列中檢索數據,作爲參數傳遞給目標 select 語句。
-->
<association property="user" javaType="com.liang.domain.User" select="com.liang.dao.UserDao.findById" column="uid">
</association>
</resultMap>
<!--查詢所有賬戶信息,同時包含其用戶信息-->
<select id="findAll" resultMap="accountMap">
select *from account;
</select>
<!--根據id查詢用戶-->
<select id="findById" resultType="User" parameterType="int">
<include refid="querySql"></include> where id= #{userID};
</select>
- 編寫測試方法
/**
* 查詢所有賬戶信息,同時包含其用戶信息【延遲加載】
*/
@Test
public void testFindAll()
{
List<Account> accounts = accountDao.findAll();
}
- 開啓延遲加載策略
<settings>
<!--
lazyLoadingEnabled : 延遲加載的全局開關。當開啓時,所有關聯對象都會延遲加載。
aggressiveLazyLoading : 當開啓時,任何方法的調用都會加載該對象的所有屬性
-->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
此時執行程序的日誌爲:
而當沒有延時加載時,程序執行日誌爲:
可以看出:當沒有延時加載時候,採用的是立即加載策略。
collection的延時加載
要求:查詢用戶信息,同時按需加載賬戶信息。
- 編寫實體類
package com.liang.domain;
import java.util.Date;
import java.util.List;
/**
* 用戶類
*/
public class User {
private int id;
private String username;
private Date birthday;
private String sex;
private String address;
private List<Account> accounts;
public List<Account> getAccounts() {
return accounts;
}
public void setAccounts(List<Account> accounts) {
this.accounts = accounts;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", birthday=" + birthday +
", sex='" + sex + '\'' +
", address='" + address + '\'' +
'}';
}
}
package com.liang.domain;
import java.io.Serializable;
/**
* 賬戶實體類
*/
public class Account implements Serializable {
private int id;
private int uid;
private Double money;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", uid=" + uid +
", money=" + money +
'}';
}
}
- 編寫持久層接口類方法
package com.liang.dao;
import com.liang.domain.User;
import java.util.List;
public interface UserDao{
/**
* 查詢所有用戶
* @return
*/
List<User> findAll();
}
package com.liang.dao;
import com.liang.domain.Account;
import java.util.List;
/**
* 賬戶的持久層接口
*/
public interface AccountDao {
/**
* 通過用戶id查詢賬戶信息
* @param uid
* @return
*/
List<Account> findByUid(int uid);
}
- 編寫持久層映射文件
<?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.liang.dao.UserDao">
<resultMap id="userMap" type="com.liang.domain.User">
<id column="id" property="id"></id>
<result property="username" column="username"></result>
<result property="sex" column="sex"></result>
<result property="address" column="address"></result>
<result property="birthday" column="birthday"></result>
<collection property="accounts" select="com.liang.dao.AccountDao.findByUid" column="id"></collection>
</resultMap>
<select id="findAll" resultMap="userMap">
select *from user;
</select>
</mapper>
<?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.liang.dao.AccountDao">
<select id="findByUid" parameterType="int" resultType="com.liang.domain.Account">
select *from account where uid = #{uid}
</select>
</mapper>
- 編寫測試方法
import com.liang.dao.UserDao;
import com.liang.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 TestMyBatis {
private SqlSession sqlSession = null;
private InputStream inputStream = null;
private UserDao userDao = null;
@Before
public void init() throws IOException {
inputStream = Resources.getResourceAsStream("SqlConfig.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
sqlSession = sqlSessionFactory.openSession();
userDao = sqlSession.getMapper(UserDao.class);
}
@After
public void destroy() throws IOException {
sqlSession.commit();
sqlSession.close();
inputStream.close();
}
/**
* 查詢所有用戶信息
*/
@Test
public void testFindAll() {
List<User> users = userDao.findAll();
}
}
- 開啓延遲加載策略
<settings>
<!--
lazyLoadingEnabled : 延遲加載的全局開關。當開啓時,所有關聯對象都會延遲加載。
aggressiveLazyLoading : 當開啓時,任何方法的調用都會加載該對象的所有屬性
-->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
經測試,開啓延時加載時,程序執行日誌爲: