文章目录
一、需求
查询账户(Account)信息并且会关联查询用户(User)的所有信息。如果只需要查询账户(Account)信息即可满足需求,当我们需要查询用户(User)信息的时时候再去进行查询用户(User)信息。
解决以上需求将用到延迟加载的知识。
二、什么是延迟加载
1. 延迟加载的定义
延迟加载 就是在需要 用到数据时才进行加载 ,不需要用到数据时就不进行加载数据。 延迟加载也称为懒加载. 。
2. 延迟加载的利与弊
好处:先从单表进行查询数据,需要时再从关联表去关联查询,将会提高数据库性能,因为查询单表要比关联查询多张表速度快。
坏处: 因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降。
三、准备开发环境
1. 数据库表
User表
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(32) NOT NULL COMMENT '用户名称',
`sex` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '性别',
`birthday` datetime DEFAULT NULL COMMENT '生日',
`address` varchar(256) DEFAULT NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
Account表
CREATE TABLE `account` (
`ID` int(11) NOT NULL COMMENT '编号',
`UID` int(11) DEFAULT NULL COMMENT '用户编号',
`MONEY` double DEFAULT NULL COMMENT '金额',
PRIMARY KEY (`ID`),
KEY `FK_Reference_8` (`UID`),
CONSTRAINT `FK_Reference_8` FOREIGN KEY (`UID`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2. 编写配置文件
jdbcConfig.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis_study?characterEncoding=utf8
jdbc.username=root
jdbc.password=root
Mybatis-config.xml
<configuration>
<!-- 配置properties -->
<properties resource="jdbcConfig.properties"></properties>
<!-- 使用typeAliases配置别名,只能配置pojo中的别名-->
<typeAliases>
<package name="com.zxy.pojo"/>
</typeAliases>
<!-- 配置环境 -->
<environments default="mysql">
<!-- 配置mysql环境 -->
<environment id="mysql">
<!-- 配置事务 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置连接池 -->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
</configuration>
四、项目结构图
五、一对一关系中配置延迟加载
1. 创建用户和账户实体类
用户实体类 User.java
public class User implements Serializable {
private Integer id;
private String username;
private String sex;
private Date birthday;
private String address;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", sex='" + sex + '\'' +
", birthday=" + birthday +
", address='" + address + '\'' +
'}';
}
}
账户实体类 Account.java
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money;
// 从表实体应该包含一个主表实体的对象应用,和用户表构成一对一的关系,即一个账号只能由一个用户创建
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUid() {
return uid;
}
public void setUid(Integer 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 +
'}';
}
}
2. 创建 IAccountDao 接口和 IAccountDao.xml 文件
IAccountDao
public interface IAccountDao {
/**
* 查询所有账户信息
*
* @return
*/
List<Account> findAll();
}
IAccountDao.xml
<mapper namespace="com.zxy.dao.IAccountDao">
<!-- 定义封装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>
<!-- 一对一的关系映射,配置封装User的内容
select 属性指定的内容:查询用户的唯一标识
column属性指定的内容:用户根据id 查询时,所需要的参数值
-->
<association property="user" column="uid" javaType="User" select="com.zxy.dao.IUserDao.findById"></association>
</resultMap>
<!-- 查询所有账户信息 -->
<select id="findAll" resultMap="accountUserMap">
SELECT
*
FROM
account
</select>
</mapper>
3 .在 Mybatis-config.xml 配置文件中注册映射文件
<!-- 配置映射文件的位置-->
<mappers>
<package name="com.zxy.dao"/>
</mappers>
4. 在 Mybatis-config.xml 配置文件中开启懒加载配置
<settings>
<!-- 开启mybatis 全局支持延迟加载 -->
<!-- 全局性设置懒加载。如果设为‘false',则所有相关联的都会被初始化加载。 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 当设置为‘true'的时候,懒加载的对象可能被任何懒属性全部加载。否则,每个属性都按需加载。-->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
5. 测试类(只查询账户信息)
AccountTest
public class AccountTest {
private InputStream input;
private SqlSession session;
private IAccountDao accountDao;
/**
* 初始化操作
*
* @throws Exception
*/
@Before // 用于在测试方法执行之前执行
public void init() throws Exception {
// 1.读取配置文件
input = Resources.getResourceAsStream("Mybatis-config.xml");
// 2.获取SqlSessionFactory工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(input);
// 3.获取SqlSession 对象
session = factory.openSession();
// 4.获取dao接口的代理对象
accountDao = session.getMapper(IAccountDao.class);
}
@After // 用于在测试方法执行之后执行
public void destroy() throws Exception {
// 提交事务
session.commit();
// 释放资源
session.close();
input.close();
}
/**
* 查询所有账户信息
*/
@Test
public void testFindAll() {
List<Account> accounts = accountDao.findAll();
}
}
可以看出它只执行了一条语句,只查询了账户的信息,没有查询用户信息。因为本次只是将Account对象查询出来放入List集合中,并没有涉及到User对象,所以就没有发出SQL语句查询账户所关联的User对象的查询。
二、一对多关系中配置延迟加载
1.在User实体类中加入List属性
// 一对多关系映射,一个用户能创建多个账号,用户和账号构成一对多的关系
List<Account> accounts;
public List<Account> getAccounts() {
return accounts;
}
public void setAccounts(List<Account> accounts) {
this.accounts = accounts;
}
2. 创建用户和账户持久层接口的方法
public interface IAccountDao {
/**
* 查询所有账户信息
*
* @return
*/
List<Account> findAll();
/**
* 根据用户id查询账户信息
* @param uid
* @return
*/
List<Account> findAccountByUid(Integer uid);
}
3. 编写用户持久层映射配置
<mapper namespace="com.zxy.dao.IUserDao">
<!-- 定义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" select="com.zxy.dao.IAccountDao.findAccountByUid" column="id"></collection>
</resultMap>
<!--查询所有-->
<select id="findAll" resultMap="userAccountMap">
SELECT
*
FROM
user
</select>
<!-- 根据id查询用户信息 -->
<select id="findById" parameterType="int" resultType="com.zxy.pojo.User">
select
id as userId,
username as userName,
address as userAddress,
sex as userSex,
birthday as userBirthday
from
user
where
id=#{uid}
</select>
</mapper>
4. 编写账户持久层映射配置
<!-- 根据用户id查询账户列表 -->
<select id="findAccountByUid" resultType="Account">
SELECT
*
FROM
account
WHERE
uid = #{uid}
</select>
5. 测试类(只查询用户信息)
public class UserTest {
private InputStream input;
private SqlSession session;
private IUserDao userDao;
/**
* 初始化操作
*
* @throws Exception
*/
@Before // 用于在测试方法执行之前执行
public void init() throws Exception {
// 1.读取配置文件
input = Resources.getResourceAsStream("Mybatis-config.xml");
// 2.获取SqlSessionFactory工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(input);
// 3.获取SqlSession 对象
session = factory.openSession();
// 4.获取dao接口的代理对象
userDao = session.getMapper(IUserDao.class);
}
@After // 用于在测试方法执行之后执行
public void destroy() throws Exception {
// 提交事务
session.commit();
// 释放资源
session.close();
input.close();
}
/**
* 测试查询所有账户信息
*/
@Test
public void testFindAll() {
List<User> users = userDao.findAll();
}
}
发现只是查询用户,并没有加载Account账户信息。