Mybatis学习(5)延迟加载(懒加载)

一、需求

查询账户(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账户信息。

发布了73 篇原创文章 · 获赞 796 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/weixin_43570367/article/details/103317296