MyBatis 延迟加载
总结: 核心是: 在需要延迟查询的association或者collection中配置select和fetchType属性
前者select配置的是要延迟查询的dao方法
后者fetchType属性配置的是要eager或者lazy加载, 默认是eager
作用: 需要的时候才查询, 减少数据库压力
需求: 查询Account与关联表User, 测试延迟加载User
代码示例
1, 准备两张表
create table user
(
uid int primary key auto_increment,
username varchar(40),
sex varchar(10),
birthday date,
address varchar(40)
);
insert into user values (null,'Mark1','male','1999-01-01','Beijing');
insert into user values (null,'Mark2','male','1999-01-01','Beijing');
insert into user values (null,'Mark3','male','1999-01-01','Beijing');
insert into user values (null,'Mark4','male','1999-01-01','Beijing');
insert into user values (null,'Mark5','male','1999-01-01','Beijing');
CREATE TABLE account(
aid INT PRIMARY KEY auto_increment,
money DOUBLE,
uid INT
);
ALTER TABLE account ADD FOREIGN KEY(uid) REFERENCES user(uid);
INSERT INTO `t_account` VALUES (null, '1000', '1');
INSERT INTO `t_account` VALUES (null, '2000', '1');
INSERT INTO `t_account` VALUES (null, '1000', '2');
INSERT INTO `t_account` VALUES (null, '2000', '2');
INSERT INTO `t_account` VALUES (null, '800', '3');
2, 实体Bean
实体Bean: Account
import lombok.Data;
import java.io.Serializable;
/**
* @Date 2021/2/8
*/
@Data
public class Account implements Serializable {
private Integer aid;
private Double money;
private Integer uid;
// 关联查询的表
private User user;
}
实体Bean: User
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
/**
* @Date 2021/2/4
*/
@Data
public class User implements Serializable {
private int uid;
private String username;
private String sex;
private Date birthday;
private String address;
}
3, Dao
Dao接口: AccountDao
import com.nengli51.pojo.Account;
public interface AccountDao {
/**
* 根据aid查找Account记录
* @param aid
* @return
*/
Account findAccountById(Integer aid);
}
Dao接口: UserDao
import com.nengli51.pojo.User;
import java.util.List;
public interface UserDao {
/**
* 根据id查询user记录
* @param uid
* @return
*/
User findUserByUid(int uid);
}
4, Mapper配置文件
Mapper配置文件: AccountDao.xml
延迟加载的配置关键: 在Account的自定义映射关系中, 设置延迟加载的User
<?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.nengli51.dao.AccountDao">
<cache></cache>
<!-- 自定义映射关系 -->
<resultMap id="accountUserMap" type="Account">
<id column="aid" property="aid"></id>
<result column="money" property="money"></result>
<result column="uid" property="uid"></result>
<!-- 延迟加载的配置关键
一对一映射
select属性表示调用其它的select标签
column属性表示往要调用的其它的select标签中传入参数
fetchType="lazy"表示延迟加载(局部配置,只有配置了这个的地方才会延迟加载)
-->
<association column="uid" property="user" javaType="User" select="com.nengli51.dao.UserDao.findUserByUid" fetchType="lazy"></association>
</resultMap>
<select id="findAccountById" parameterType="int" resultMap="accountUserMap">
select * from account where aid=#{aid}
</select>
</mapper>
Mapper配置文件: 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.nengli51.dao.UserDao">
<select id="findUserByUid" parameterType="int" resultType="User">
select * from user where uid=#{uid}
</select>
</mapper>
5, 测试
分别进行两次测试, 代码一样, 不同之处是修改AccountDao.xml的fetchType配置, 分别测试并查看日志输出
import com.nengli51.dao.AccountDao;
import com.nengli51.pojo.Account;
import com.nengli51.pojo.User;
import com.nengli51.utils.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
/**
* @Date 2021/2/9
*/
public class TestLazyLoad {
@Test
public void testMethod(){
SqlSession sqlSession = MyBatisUtils.getSqlSessionFactory().openSession();
AccountDao accountDao = sqlSession.getMapper(AccountDao.class);
Account account = accountDao.findAccountById(1);
System.out.println(account.getMoney());
//进行延迟加载的时候开启之后, 才会发送对关联表的查询
//User user = account.getUser();
//System.out.println(user);
MyBatisUtils.commitAndClose(sqlSession);
}
}
fetchType="lazy"的测试结果, 即, 开启了延迟加载的情况, 可以看到进行了一次SQL查询.(打开上面代码的注释, 才会发送第二条SQL)
==> Preparing: select * from account where aid=?
==> Parameters: 1(Integer)
<== Columns: aid, money, uid
<== Row: 1, 1000, 1
<== Total: 1
1000.0
fetchType="eager"的测试结果, 可以看到进行了两次SQL查询(关掉代码的注释, 但是依然会自动发送对关联表的查询)
==> Preparing: select * from account where aid=?
==> Parameters: 1(Integer)
<== Columns: aid, money, uid
<== Row: 1, 1000, 1
<== Total: 1
1000.0
==> Preparing: select * from user where uid=?
==> Parameters: 1(Integer)
<== Columns: uid, username, sex, birthday, address
<== Row: 1, Mark1, male, 1985-01-01, Beijing
<== Total: 1
User(uid=1, username=Mark1, sex=male, birthday=Tue Jan 01 00:00:00 CST 1985, address=Beijing)