Mybatis中的延迟加载一对一

369 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

Mybatis中的的延迟加载、缓存和注解开发

1.Mybatis中的延迟加载

问题:在一对多中,当我们有一个用户,他有100个账户 在查询用户的时候,要不要把关联的账户查出来? 在查询账户的时候,要不要把我关联的用户查出来

在查询用户时,用户下的账户信息应该是什么时候使用,什么时候查询的

在查询账户时,账户的所属用户信息应该是睡着查询时一起查询出来的

解决:

  • 延迟加载:在真正使用数据时才发起查询,不用的时候不查询,按需加载
  • 立即加载:不管用不用,只要一调用方法,马上发起查询

在对应的四种表关系中:一对多,多对一,多对多

  • 一对多,多对多:通常情况下我们都是采用延迟加载
  • 多对一,一对一:通常情况请下我们采用立即加载 我们在查询mybatis的官方文档时,lazyLoadingEnable就是延迟加载全局开关,以及aggressiveLazyLoading调用加载该对象的属性

image.png

1.一对一代码实现:

Account实现类

package com.mybatisD.domain;

import java.io.Serializable;

/**
 * @author :程序员徐大大
 * @description:TODO
 * @date :2022-01-22 16:02
 */
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 +
                '}';
    }
}

User实现类

package com.mybatisD.domain;

import java.io.Serializable;
import java.util.Date;
import java.util.List;

public class User implements Serializable {
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;
    //多对多的关系映射,一个用户可以具备多个角色
    private List<Role> roles;

    public List<Role> getRoles() {
        return roles;
    }

    public void setRoles(List<Role> roles) {
        this.roles = roles;
    }

    private List<Account> account;
//一对多关系映射,主表实体应该包含从表实体的集合引用
    public List<Account> getAccount() {

        return account;
    }

    public void setAccount(List<Account> account) {
        this.account = account;
    }

    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 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 + '\'' +
                '}';
    }
}

IAccountDao接口

package com.mybatisD.dao;

import com.mybatisD.domain.Account;
import com.mybatisD.domain.AccountUser;

import java.util.List;

public interface IAccountDao {
    //查询所有账户
    List<Account> findAll();
    //查询账户,并且带有用户名称和地址信息
    List<AccountUser> findAllAccount();
}

IUserDao接口

package com.mybatisD.dao;


import com.mybatisD.domain.QueryVo;
import com.mybatisD.domain.User;
import org.apache.ibatis.annotations.Select;

import java.util.List;

/*
* 用户持久层接口
* */
public interface IUserDao {

   // 查询所有操作
   // @Select("select * from user") 这是用注解方法
    //根据查询一个用户
    User findById(Integer userId);
  
}

IAccountDao.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.mybatisD.dao.IAccountDao">
    <!--定义封装account的resultMap-->
    <resultMap id="accountUserMap" type="com.mybatisD.domain.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="com.mybatisD.domain.User" select="com.mybatisD.dao.IUserDao.findById"></association>
    </resultMap>
    <select id="findAll" resultMap="accountUserMap" >
        select * from account
    </select>
</mapper>

IUserDao.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.mybatisD.dao.IUserDao">
    <!--根据ID查询用户-->
    <select id="findById" parameterType="INT" resultType="com.mybatisD.domain.User">
        select * from user where id=#{userid}
    </select>
</mapper>

SqlMapConfig.xml配置文件 其中最主要的是

 <!--配置参数延迟加载-->
    <settings>
        <!--开启mybatis支持延迟加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>
<?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文件 可以在标签内部配置数据库的信息,也可以通过属性引用外部配置信息
    resource属性:用于指定配置文件的位置,是按照类路径的写法来写平且必须存在与类路径下
    -->
    <properties resource="jdbcConfig.properties">
    </properties>
    <!--配置参数延迟加载-->
    <settings>
        <!--开启mybatis支持延迟加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>
    <!--配置环境-->
    <environments default="mysql">
        <!--配置mysql环境-->
        <environment id="mysql">
            <!--配置事物类型-->
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <!--配置连接数据库的4个信息-->
                <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>
    <!--指定映射配置文件的位置,映射配置文件指的是每个到独立的配置文件-->
    <!--<mappers>
        <mapper resource="com/mybatisD/dao/IUserDao.xml"/>
     <mapper resource="com/mybatisD/dao/IAccountDao.xml"/>
    </mappers>-->
    <!--如果要是用注解来配置的话,此处应该使用class属性指定被注解的dao全限定类名-->
    <!--<mappers>
        <mapper class="com.mybatisD.dao.IUserDao"/>
    </mappers>-->
    <mappers >
        <!--package标签用于指定doa接口所在的包,当指定了之后就不需要在写mapper以及resource或者class了-->
        <package name="com.mybatisD.dao"/>
    </mappers>
</configuration>

配置日志信息log4j.properties

log4j.rootCategory=debug,CONSOLE, LOGFILE
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x -%m\n
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=d:\axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x -%m\n

配置jdbc.properties数据库

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/newsql?characterEncoding=utf-8
jdbc.username=root
jdbc.password=

测试类

package com.mybatisJ.test;

import com.mybatisD.dao.IAccountDao;
import com.mybatisD.dao.IUserDao;
import com.mybatisD.domain.Account;
import com.mybatisD.domain.AccountUser;
import com.mybatisD.domain.QueryVo;
import com.mybatisD.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.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author :程序员徐大大
 * @description:TODO
 * @date :2022-01-22 16:07
 */
public class AccountTest {
    private InputStream in;
    private SqlSession sqlSession;
    private IAccountDao  accountDao;

    @Before//用于在测试方法执行之前执行
    public void init()throws  Exception{
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(in);
        sqlSession = factory.openSession();
        //4.使用SqlSession创建Dao接口的代理对象
        accountDao = sqlSession.getMapper(IAccountDao.class);
    }
    @After//用于在测试方法之后执行
    public void destory() throws Exception{
        //添加提交事物,不添加无法提交
        sqlSession.commit();
        sqlSession.close();
        in.close();
    }
    //查询连接方法其中包括用户的一些信息
    @Test
    public  void testFindAll() throws  Exception{

        List<Account> accounts = accountDao.findAll();
        for (Account account: accounts) {
            System.out.println("-----------------------");
            System.out.println(account);
           System.out.println(account.getUser());
        }
    }
    //查询account的信息
    @Test
    public void findAllAccount(){
        List<AccountUser> accountUsers = accountDao.findAllAccount();
        for (AccountUser au: accountUsers) {
            System.out.println(au);
        }
    }
}

image.png

没有配置延迟加载时数据都是直接加载出来的

image.png

其他信息

image.png