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)