Java笔记之Mybatis(七):延迟加载

1.新建Java Project: mybatis_demo2

2.项目下新建文件夹lib,导入jar包,新加了log4j日志jar包

3.src目录下创建log4j.properties文件

log4j.rootLogger=DEBUG,stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

4.新建mybatisConfig.xml文件

<?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>
    <settings>
        <!-- 开启驼峰命名规则映射 -->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    <!-- 对类起别名 -->
    <typeAliases>
        <!-- 类的别名默认为类名 -->
        <package name="com.mybatis.demo2.pojo"/>
    </typeAliases>
    <environments default="development">
        <environment id="development">
            <!-- 使用JDBC事务管理 -->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 定义数据库连接池 -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/keeper?characterEncoding=utf-8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <!-- 配置sql映射配置文件 -->
    <mappers>
        <mapper resource="com/mybatis/demo2/pojo/Employee.xml"/>
        <mapper resource="com/mybatis/demo2/pojo/Department.xml"/>
    </mappers>
</configuration>

5.在包com.mybatis.demo2.pojo下创建Employee类、Department类、Employee.xml、Department.xml

Employee类:

package com.mybatis.demo2.pojo;

public class Employee {
    private int empId;
    private String empName;
    private Department department;
    
    public int getEmpId() {
        return empId;
    }
    public void setEmpId(int empId) {
        this.empId = empId;
    }
    public String getEmpName() {
        return empName;
    }
    public void setEmpName(String empName) {
        this.empName = empName;
    }
    public Department getDepartment() {
        return department;
    }
    public void setDepartment(Department department) {
        this.department = department;
    }
}

Department类:

package com.mybatis.demo2.pojo;

import java.util.List;

public class Department {
    private int deptId;
    private String deptName;
    private List<Employee> employees;
    public int getDeptId() {
        return deptId;
    }
    public void setDeptId(int deptId) {
        this.deptId = deptId;
    }
    public String getDeptName() {
        return deptName;
    }
    public void setDeptName(String deptName) {
        this.deptName = deptName;
    }
    public List<Employee> getEmployees() {
        return employees;
    }
    public void setEmployees(List<Employee> employees) {
        this.employees = employees;
    } 
    
}

Employee.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.mybatis.demo2.pojo">
    <select id="getEmployeesByDeptId" parameterType="int" resultType="Employee">
        select * from t_employee where dept_id=#{value}
    </select>
        
</mapper>

Department.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.mybatis.demo2.pojo">
    <select id="getDepartmentById" parameterType="int" resultMap="departmentResultMap">
        select * from t_department where dept_id=#{value}
    </select>
    <resultMap type="Department" id="departmentResultMap">
        <collection property="employees" ofType="Employee" javaType="java.util.ArrayList"
        select="getEmployeesByDeptId" column="dept_id"></collection>
    </resultMap>
</mapper>

6.在包com.mybatis.demo2.test新建MybatisTest类

package com.mybatis.demo2.test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

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 com.mybatis.demo2.pojo.Department;
import com.mybatis.demo2.pojo.Employee;

public class MybatisTest {

    public static void main(String[] args) throws IOException {
        //加载mybatis的配置文件
        InputStream inputStream = Resources.getResourceAsStream("mybatisConfig.xml");
        //获取SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //使用SqlSessionFactory对象创建SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        Department department = sqlSession.selectOne("getDepartmentById",1);
        System.out.println(department.getDeptName());
        System.out.println("================================");
        List<Employee> employees = department.getEmployees();
        for (Employee employee : employees) {
            System.out.println(employee.getEmpName());
        }
    }

}

7.运行MybatisTest类,查看日志

DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Created connection 112061925.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@6adede5]
DEBUG [main] - ==>  Preparing: select * from t_department where dept_id=? 
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - ====>  Preparing: select * from t_employee where dept_id=? 
DEBUG [main] - ====> Parameters: 1(Integer)
DEBUG [main] - <====      Total: 3
DEBUG [main] - <==      Total: 1
行政部
================================
张三
李四
王五

从代码和日志中可以看出,分割线之前只是查看了Department实例的deptName属性值,也把关联的员工信息查了出来,这就需要进行延迟加载了,在真正使用到关联的信息时才去查询.

8.修改mybatisConfig.xml,添加关于延迟加载的配置

<?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>
    <settings>
        <!-- 开启驼峰命名规则映射 -->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <!-- 开启延时加载 -->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!-- 将积极加载改为消极加载,也就是按需加载 -->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>
    <!-- 对类起别名 -->
    <typeAliases>
        <!-- 类的别名默认为类名 -->
        <package name="com.mybatis.demo2.pojo"/>
    </typeAliases>
    <environments default="development">
        <environment id="development">
            <!-- 使用JDBC事务管理 -->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 定义数据库连接池 -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/keeper?characterEncoding=utf-8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <!-- 配置sql映射配置文件 -->
    <mappers>
        <mapper resource="com/mybatis/demo2/pojo/Employee.xml"/>
        <mapper resource="com/mybatis/demo2/pojo/Department.xml"/>
    </mappers>
</configuration>

9.再次运行MybatisTest类,查看日志

EBUG [main] - Opening JDBC Connection
DEBUG [main] - Created connection 112061925.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@6adede5]
DEBUG [main] - ==>  Preparing: select * from t_department where dept_id=? 
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 1
行政部
================================
DEBUG [main] - ==>  Preparing: select * from t_employee where dept_id=? 
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 3
张三
李四
王五

从日志信息中可以看出,只有在真正使用到员工信息的时候才进行查询,也即实现了延时加载的效果.

10.根据员工id获取员工信息,延迟加载部门信息

修改Employee.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.mybatis.demo2.pojo">
    <select id="getEmployeesByDeptId" parameterType="int" resultType="Employee">
        select * from t_employee where dept_id=#{value}
    </select>
    
    <select id="getEmployeeById" parameterType="int" resultMap="employeeMap">
        select * from t_employee where emp_id=#{value}
    </select>    
    <resultMap type="Employee" id="employeeMap">
        <association property="department" javaType="Department" select="getDepartmentByDeptId" column="dept_id"></association>
    </resultMap>
</mapper>

修改Department.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.mybatis.demo2.pojo">
    <select id="getDepartmentById" parameterType="int" resultMap="departmentResultMap">
        select * from t_department where dept_id=#{value}
    </select>
    <resultMap type="Department" id="departmentResultMap">
        <collection property="employees" ofType="Employee" javaType="java.util.ArrayList"
        select="getEmployeesByDeptId" column="dept_id"></collection>
    </resultMap>
    
    <select id="getDepartmentByDeptId" parameterType="int" resultType="Department">
        select * from t_department where dept_id=#{value}
    </select>
</mapper>

新建MybatisTest2类

package com.mybatis.demo2.test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

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 com.mybatis.demo2.pojo.Department;
import com.mybatis.demo2.pojo.Employee;

public class MybatisTest2 {

    public static void main(String[] args) throws IOException {
        //加载mybatis的配置文件
        InputStream inputStream = Resources.getResourceAsStream("mybatisConfig.xml");
        //获取SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //使用SqlSessionFactory对象创建SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        Employee employee = sqlSession.selectOne("getEmployeeById",1);
        System.out.println(employee.getEmpName());
        System.out.println("================================");
        Department department = employee.getDepartment();
        System.out.println(department.getDeptName());
    }

}

运行MybatisTest2类,查看日志

DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Created connection 112061925.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@6adede5]
DEBUG [main] - ==>  Preparing: select * from t_employee where emp_id=? 
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 1
张三
================================
DEBUG [main] - ==>  Preparing: select * from t_department where dept_id=? 
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 1
行政部

11.避免循环查询和调用

将Employee.xml中的id为employeeMap的resultMap标签下的association标签中的select属性值改为getDepartmentById

修改后的Employee.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.mybatis.demo2.pojo">
    <select id="getEmployeesByDeptId" parameterType="int" resultType="Employee">
        select * from t_employee where dept_id=#{value}
    </select>
    
    <select id="getEmployeeById" parameterType="int" resultMap="employeeMap">
        select * from t_employee where emp_id=#{value}
    </select>    
    <resultMap type="Employee" id="employeeMap">
        <association property="department" javaType="Department" select="getDepartmentById" column="dept_id"></association>
    </resultMap>
</mapper>

修改MybatisTest2类

package com.mybatis.demo2.test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

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 com.mybatis.demo2.pojo.Department;
import com.mybatis.demo2.pojo.Employee;

public class MybatisTest2 {

    public static void main(String[] args) throws IOException {
        //加载mybatis的配置文件
        InputStream inputStream = Resources.getResourceAsStream("mybatisConfig.xml");
        //获取SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //使用SqlSessionFactory对象创建SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        Employee employee = sqlSession.selectOne("getEmployeeById",1);
        System.out.println(employee.getEmpName());
        System.out.println("================================");
        Department department = employee.getDepartment();
        System.out.println(department.getDeptName());
        System.out.println("================================");
        List<Employee> employees = department.getEmployees();
        for (Employee employee2 : employees) {
            System.out.println(employee2.getEmpName());
        }
    }

}

运行MybatisTest2类,查看日志

DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Created connection 112061925.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@6adede5]
DEBUG [main] - ==>  Preparing: select * from t_employee where emp_id=? 
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 1
张三
================================
DEBUG [main] - ==>  Preparing: select * from t_department where dept_id=? 
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 1
行政部
================================
DEBUG [main] - ==>  Preparing: select * from t_employee where dept_id=? 
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 3
张三
李四
王五

从代码和日志中可以看出,原来只是想查指定id的员工信息及其部门信息,却查到了对应部门下的所有员工信息,这种是不合理的,也是不安全的,所以要避免循环查询和调用;

改回原来的getDepartmentByDeptId,再运行MybatisTest2类就会报错

DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Created connection 112061925.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@6adede5]
DEBUG [main] - ==>  Preparing: select * from t_employee where emp_id=? 
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 1
张三
================================
DEBUG [main] - ==>  Preparing: select * from t_department where dept_id=? 
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 1
行政部
================================
Exception in thread "main" java.lang.NullPointerException
    at com.mybatis.demo2.test.MybatisTest2.main(MybatisTest2.java:31)
posted @ 2020-03-31 17:15  安徒生敲代码  阅读(214)  评论(0编辑  收藏  举报