=============== MyBatis延迟加载 =============== MyBatis在封装JDBC同时,对其进行了优化,除缓存以外,还提供了延迟加载机制: - 如果在MyBatis中开启了延迟加载,在执行子查询时: - 首先执行第一次查询 - 只有在用到子查询结果时,才会触发子查询 - 如果不使用子查询的结果,子查询不会执行 - 借助延迟加载,可以减少对数据库不必要的访问 1 实体类 将Association项目cn.tedu.association.pojo包中的三个实体类 Department、Employee和DepartmentEmployees 复制到Dynamic项目cn.tedu.dynamic.pojo包中,并修改包名: package cn.tedu.dynamic.pojo; 在/src/main/java/cn.tedu.dynamic.dao目录下添加数据访问接口: 2 DAO public interface DepartmentDao { public DepartmentEmployees getDepartmentEmployees(String name); } public interface EmployeeDao { public List getEmployees(int department); } 3 配置MyBatis 在/src/main/resources/mybatis-config.xml文件中添加: ... ... ... ... ... 4 Mapper 在/src/main/resources/mappers目录下添加DepartmentMapper.xml文件: 在/src/main/resources/mappers目录下添加EmployeeMapper.xml文件: 5 测试 public class DepartmentDaoTest { @Test public void testGetDepartmentEmployees() { DepartmentDao departmentDao = MyBatisUtil.getMapper(DepartmentDao.class); DepartmentEmployees departmentEmployees = departmentDao.getDepartmentEmployees("研发部"); System.out.println(departmentEmployees.getDepartment()); } } 运行测试用例: [main] DEBUG - Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.sg :Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter. [main] DEBUG - Opening JDBC Connectionsg :Opening JDBC Connection [main] INFO - {dataSource-1} initedsg :{dataSource-1} inited [Finalizer] DEBUG - PooledDataSource forcefully closed/removed all connections.sg :PooledDataSource forcefully closed/removed all connections. [main] DEBUG - ==> Preparing: select id, name, description from t_department where name = ? sg :==> Preparing: select id, name, description from t_department where name = ? [main] DEBUG - ==> Parameters: 研发部(String)sg :==> Parameters: 研发部(String) [main] DEBUG - ====> Preparing: select number, fullname, age, department from t_employee where department = ? sg :====> Preparing: select number, fullname, age, department from t_employee where department = ? [main] DEBUG - ====> Parameters: 1(Integer)sg :====> Parameters: 1(Integer) [main] DEBUG - <==== Total: 3sg :<==== Total: 3 [main] DEBUG - <== Total: 1sg :<== Total: 1 Department(id=1, name=研发部, description=研发软件产品) 执行了两次select,第一次查询t_department表,第二次查询t_employee表。 6 开启延迟加载 在DepartmentMapper.xml文件中将子查询的fetchType属性设置为lazy: ... ... ... 运行测试用例: 报错提示空指针异常,Error creating lazy proxy. Cause: java.lang.NullPointerException ... 7 升级MyBatis 在pom.xml文件中指定依赖更高版本的MyBatis: ... org.mybatis mybatis 3.5.1 ... 运行测试用例: [main] DEBUG - Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.sg :Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter. [main] DEBUG - Opening JDBC Connectionsg :Opening JDBC Connection [main] INFO - {dataSource-1} initedsg :{dataSource-1} inited [Finalizer] DEBUG - PooledDataSource forcefully closed/removed all connections.sg :PooledDataSource forcefully closed/removed all connections. [main] DEBUG - ==> Preparing: select id, name, description from t_department where name = ? sg :==> Preparing: select id, name, description from t_department where name = ? [main] DEBUG - ==> Parameters: 研发部(String)sg :==> Parameters: 研发部(String) [main] DEBUG - <== Total: 1sg :<== Total: 1 Department(id=1, name=研发部, description=研发软件产品) 只执行了对t_department表的第一次查询。 8 使用子查询结果 修改测试用例,增加对子查询结果的使用: public class DepartmentDaoTest { @Test public void testGetDepartmentEmployees() { DepartmentDao departmentDao = MyBatisUtil.getMapper(DepartmentDao.class); DepartmentEmployees departmentEmployees = departmentDao.getDepartmentEmployees("研发部"); System.out.println(departmentEmployees.getDepartment()); System.out.println(departmentEmployees.getEmployees()); } } 运行测试用例: [main] DEBUG - Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.sg :Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter. [main] DEBUG - Opening JDBC Connectionsg :Opening JDBC Connection [main] INFO - {dataSource-1} initedsg :{dataSource-1} inited [Finalizer] DEBUG - PooledDataSource forcefully closed/removed all connections.sg :PooledDataSource forcefully closed/removed all connections. [main] DEBUG - ==> Preparing: select id, name, description from t_department where name = ? sg :==> Preparing: select id, name, description from t_department where name = ? [main] DEBUG - ==> Parameters: 研发部(String)sg :==> Parameters: 研发部(String) [main] DEBUG - <== Total: 1sg :<== Total: 1 Department(id=1, name=研发部, description=研发软件产品) [main] DEBUG - ==> Preparing: select number, fullname, age, department from t_employee where department = ? sg :==> Preparing: select number, fullname, age, department from t_employee where department = ? [main] DEBUG - ==> Parameters: 1(Integer)sg :==> Parameters: 1(Integer) [main] DEBUG - <== Total: 3sg :<== Total: 3 [Employee(number=1001, fullname=张飞, age=25, department=1), Employee(number=1002, fullname=关羽, age=30, department=1), Employee(number=1003, fullname=赵云, age=20, department=1)] 只有在实际用到子查询结果时才真正执行子查询操作。 9 提前关闭会话 修改测试用例,在使用子查询结果之前关闭会话: public class DepartmentDaoTest { @Test public void testGetDepartmentEmployees() { DepartmentDao departmentDao = MyBatisUtil.getMapper(DepartmentDao.class); DepartmentEmployees departmentEmployees = departmentDao.getDepartmentEmployees("研发部"); System.out.println(departmentEmployees.getDepartment()); MyBatisUtil.closeSession(); System.out.println(departmentEmployees.getEmployees()); } } 运行测试用例: [main] DEBUG - Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.sg :Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter. [main] DEBUG - Opening JDBC Connectionsg :Opening JDBC Connection [main] INFO - {dataSource-1} initedsg :{dataSource-1} inited [Finalizer] DEBUG - PooledDataSource forcefully closed/removed all connections.sg :PooledDataSource forcefully closed/removed all connections. [main] DEBUG - ==> Preparing: select id, name, description from t_department where name = ? sg :==> Preparing: select id, name, description from t_department where name = ? [main] DEBUG - ==> Parameters: 研发部(String)sg :==> Parameters: 研发部(String) [main] DEBUG - <== Total: 1sg :<== Total: 1 Department(id=1, name=研发部, description=研发软件产品) [main] DEBUG - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@7d64e326]sg :Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@7d64e326] [main] DEBUG - Opening JDBC Connectionsg :Opening JDBC Connection [main] DEBUG - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@7d64e326]sg :Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@7d64e326] [main] DEBUG - ==> Preparing: select number, fullname, age, department from t_employee where department = ? sg :==> Preparing: select number, fullname, age, department from t_employee where department = ? [main] DEBUG - ==> Parameters: 1(Integer)sg :==> Parameters: 1(Integer) [main] DEBUG - <== Total: 3sg :<== Total: 3 [main] DEBUG - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@7d64e326]sg :Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@7d64e326] [main] DEBUG - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@7d64e326]sg :Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@7d64e326] [Employee(number=1001, fullname=张飞, age=25, department=1), Employee(number=1002, fullname=关羽, age=30, department=1), Employee(number=1003, fullname=赵云, age=20, department=1)] 子查询的延迟执行不受会话提前关闭的影响。 例程:Dynamic