MyBatis

Mybatis上手教程–select语句延迟加载配置和使用案例

一延迟加载说明

前面,我们利用select语句的resultMap和association标签,完成了一个分步查询的场景。先查询员工信息,并获取员工所在部门id,然后根据这个部门id去查询员工所在部门信息。如果,使用log4j打印日志的时候,会看到数据库前后执行了2条SQL语句。

那么,如果我现在的场景是只需要查询员工信息,并不需要查询员工所在部门信息的话,是不是可以让它只执行查询员工信息的SQL语句,不去查部门表;等到我将来如果需要查询部门信息的时候,再去查部门表呢?

这在Mybatis里是可以实现的。通过设置lazyLoadingEnabled和aggresiveLazyLoading这2个属性值来实现。

二配置并使用延迟加载流程

0 配置log4j记录执行SQL并输出到console

首先,在pom.xml文件里,引入log4j,当然,这个步骤在最开始的上手教程里,已经完成了。

    <dependency>
     <groupId>log4j</groupId>
     <artifactId>log4j</artifactId>
     <version>1.2.17</version>
   </dependency>

然后,参考Mybatis官网「https://mybatis.org/mybatis-3/logging.html」,在resources路径下,新建名为log4j.properties的配置文件:

# Global logging configuration
log4j.rootLogger=DEBUG,stdout
# MyBatis logging configuration...
log4j.logger.com.knockatdatabase.EmployeeMapper=TRACE
log4j.logger.com.knockatdatabase.DepartmentMapper=TRACE
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

日志级别,先配置为DEBUG,然后针对com.knockatdatabase.EmployeeMapper和com.knockatdatabase.DepartmentMapper这2个接口实施日志记录。当然,我只是快速浏览一下官网,具体配置回头深入查看一下官网。

这样,在执行完测试的Java代码之后,在控制台上,可以看到下述记录的日志信息:

    @Test
   public void testGetEmployeeAndDepartmentByIdStep() {
       String resource = "mybatis-config.xml";
       SqlSession sqlSession = null;
       try{
           InputStream inputStream = Resources.getResourceAsStream(resource);
           SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
           sqlSession = sqlSessionFactory.openSession();
           EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
           Employee employeeAndDepartmentById = mapper.getEmployeeAndDepartmentByIdStep(1);
           System.out.println("employee info: " + employeeAndDepartmentById);
           Department department = employeeAndDepartmentById.getDepartment();
           System.out.println("department info:" + department);
      } catch (IOException e) {
           e.printStackTrace();
      } finally {
           sqlSession.close();
      }
  }
//控制台日志输出:
DEBUG [main] - Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Created connection 825658265.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@31368b99]
DEBUG [main] - ==>  Preparing: select * from tbl_employee where id=?
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 1
DEBUG [main] - ==>  Preparing: select id,dept_name as deptName from tbl_dept where id=?
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 1
employee info: Employee{id=1, lastName='黄伟', gender='男', mail='huangwei@knockatdatabase.com', department=Department{id=1, deptName='市场部'}}
department info:Department{id=1, deptName='市场部'}
DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@31368b99]
DEBUG [main] - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@31368b99]
DEBUG [main] - Returned connection 825658265 to pool.

至此,可以看到,这个测试代码,执行了2条SQL,并分别打印在了控制台上。

1配置mybatis-config.xml文件
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>

这2个设置项,设置在settings标签下。lazyLoadingEnabled设置为true,表示全局开启懒加载模式;

aggresiveLazyLoading务必要设置为false。官方文档(官网下载压缩包,解压之后的PDF格式文档)是这么解释的,When enabled, any method call will load all the lazy properties of the object.

2改写测试Java代码
    @Test
   public void testGetEmployeeAndDepartmentByIdStep() {
       String resource = "mybatis-config.xml";
       SqlSession sqlSession = null;
       try{
           InputStream inputStream = Resources.getResourceAsStream(resource);
           SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
           sqlSession = sqlSessionFactory.openSession();
           EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
           Employee employeeAndDepartmentById = mapper.getEmployeeAndDepartmentByIdStep(1);
           System.out.println("employee info: " + employeeAndDepartmentById.getLastName());
//           Department department = employeeAndDepartmentById.getDepartment();
//           System.out.println("department info:" + department);
      } catch (IOException e) {
           e.printStackTrace();
      } finally {
           sqlSession.close();
      }
  }

//结果:
DEBUG [main] - Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Created connection 825658265.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@31368b99]
DEBUG [main] - ==>  Preparing: select * from tbl_employee where id=?
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 1
employee info: 黄伟
DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@31368b99]
DEBUG [main] - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@31368b99]
DEBUG [main] - Returned connection 825658265 to pool.

此时,如果我们的Java代理里不需要取部门信息时,则可以看到SQL语句只执行了1条select * from tbl_employee where id=?,并没有执行查询部门信息的SQL语句。

反之,当我们的SQL语句,需要查询部门表的字段时,才会去执行查询部门表的SQL语句:

@Test
   public void testGetEmployeeAndDepartmentByIdStep() {
       String resource = "mybatis-config.xml";
       SqlSession sqlSession = null;
       try{
           InputStream inputStream = Resources.getResourceAsStream(resource);
           SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
           sqlSession = sqlSessionFactory.openSession();
           EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
           Employee employeeAndDepartmentById = mapper.getEmployeeAndDepartmentByIdStep(1);
           System.out.println("employee info: " + employeeAndDepartmentById.getDepartment());
//           Department department = employeeAndDepartmentById.getDepartment();
//           System.out.println("department info:" + department);
      } catch (IOException e) {
           e.printStackTrace();
      } finally {
           sqlSession.close();
      }
  }

//结果:
DEBUG [main] - Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Created connection 825658265.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@31368b99]
DEBUG [main] - ==>  Preparing: select * from tbl_employee where id=?
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 1
DEBUG [main] - ==>  Preparing: select id,dept_name as deptName from tbl_dept where id=?
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 1
employee info: Department{id=1, deptName='市场部'}
DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@31368b99]
DEBUG [main] - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@31368b99]
DEBUG [main] - Returned connection 825658265 to pool.

三 小结

这个应该只能算是Mybatis的一个小功能吧,实际生产中真的会用到这种场景吗?暂且,先练手测试一把,记录一下即可。不过,也顺便快速上手了一下log4j的配置和使用。

留言

您的电子邮箱地址不会被公开。 必填项已用*标注