mybatis-映射器-级联性能分析
2017-06-17 10:56
281 查看
一:性能分析N+1问题
级联的优势就是能够方便快捷的获取数据。比如学生和学生成绩信息往往是最常用的级联信息,这个时候级联完全是有必要的,级联最好不要超过三层,多层级联会导致复杂性的增加,不利于理解和维护。同时级联也存在严重的问题,例如我只对学生课程和成绩感兴趣,就不用取出学生证和健康情况表了。因为取出学生证和健康表不但没有意义而且还会多执行sql,导致性能下降。
级联还有更严重的问题,假设表关联到Student表里面,那么可以想象,我们还要增加级联关系到这个结果集里,那么级联关系将会异常复杂。如果我们采取类似默认的场景那么有一个关联我们就要多执行一次sql,每次取出一个Student对象,那么它所有信息都会被取出来,这样造成sql执行过多,导致性能下降,这就是N+1问题,为了解决这个问题我们可以考虑延迟加载的功能。
二:延迟加载
为了处理N+1问题,mybatis引入了延迟加载的功能,延迟加载的意义在于一开始并不取出级联数据,只有当使用它了才发送sql去取回数据。
mybatis的配置中有两个全局的参数lazyLoadingEnabled和aggressiveLazyLoading。lazyLoadingEnable的含义是是否开启延迟加载功能。aggressiveLazyLoading的含义是对任意延迟属性的调用会使带有延迟加载属性的对象完整加载;反之每种属性按需加载。
mybatis默认情况都是及时加载的,现在修改mybatis配置问题settings元素里面的lazyLoadingEnabled值开启延迟加载,使得关联属性都按需加载,而不自动加载。
<?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="org/mybatis/config/database.properties" />
<settings>
<setting name="logImpl" value="LOG4J" />
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
<!-- 定义类的别名 -->
<typeAliases>
<typeAlias type="org.mybatis.pojo.Role" alias="role" />
</typeAliases>
<!-- 定义数据库信息,默认使用development数据库构建环境 -->
<environments default="development">
<environment id="development">
<!--采用jdbc事务管理 -->
<transactionManager type="JDBC">
<property name="autoCommit" value="false" />
</transactionManager>
<!-- 配置数据库连接信息 -->
<dataSource type="POOLED">
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/mapper/RoleMapper.xml" />
<mapper resource="org/mybatis/mapper/userMapper.xml" />
<mapper resource="org/mybatis/mapper/StudentMapper.xml" />
<mapper resource="org/mybatis/mapper/StudentCardMapper.xml" />
<mapper resource="org/mybatis/mapper/StudentLectureMapper.xml" />
<mapper resource="org/mybatis/mapper/LectureMapper.xml" />
<mapper resource="org/mybatis/mapper/MaleStudentMapper.xml" />
<mapper resource="org/mybatis/mapper/FemaleStudentMapper.xml" />
</mappers>
</configuration>
测试程序修改如下:
package org.mybatis.test;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.mapper.StudentMapper;
import org.mybatis.pojo.FemaleStudent;
import org.mybatis.pojo.MaleStudent;
import org.mybatis.pojo.Student;
import org.mybatis.util.SqlSessionFactoryUtil;
public class MybatisMainTest5 {
public static void main(String[] args) {
// TODO Auto-generated method stub
SqlSession sqlSession = null;
try {
sqlSession = SqlSessionFactoryUtil.openSqlSession();
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
Student student = studentMapper.getStudent(1);
// 打印学生对象
System.out.println("the student is : " + student);
// StudentLecture studentLecture =
// student.getStudentLectureList().get(0);
// 打印成绩信息
// System.out.println("成绩信息:" + studentLecture);
// System.out.println("打印课程信息:" + studentLecture.getLecture());
// 判断是男性还是女性
if (student instanceof MaleStudent) {
MaleStudent maleStudent = (MaleStudent) student;
System.out.println("打印男学生健康检查信息: " + maleStudent.getStudentHealthMaleList().get(0));
} else {
FemaleStudent maleStudent = (FemaleStudent) student;
System.out.println("打印女学生健康检查信息: " + maleStudent.getStudentHealthFemaleList().get(0));
}
} catch (Exception e) {
System.err.println(e.getMessage());
sqlSession.rollback();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
}
测试结果如下:
org.apache.ibatis.transaction.jdbc.JdbcTransaction: Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@79be0360]
DEBUG 2017-06-17 10:22:52,587 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Preparing: select id,name,sex,card_no,note from t_student where id = ?
DEBUG 2017-06-17 10:22:52,622 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 1(Integer)
DEBUG 2017-06-17 10:22:52,748 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <== Total: 1
DEBUG 2017-06-17 10:22:52,748 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Preparing: select id,student_id,native_place,issue_date,end_date,note from t_student_card where student_id =?
DEBUG 2017-06-17 10:22:52,749 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 1(Integer)
DEBUG 2017-06-17 10:22:52,751 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <== Total: 1
DEBUG 2017-06-17 10:22:52,751 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Preparing: select id,student_id,lecture_id,grade,note from t_student_lecture where student_id = ?
DEBUG 2017-06-17 10:22:52,751 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 1(Integer)
DEBUG 2017-06-17 10:22:52,757 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <== Total: 1
DEBUG 2017-06-17 10:22:52,757 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Preparing: select id,student_id studentId,check_date checkDate,heart, liver,spleen,lung,kidney,uterus,note from t_student_health_female where student_id = ?
DEBUG 2017-06-17 10:22:52,757 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 1(Integer)
DEBUG 2017-06-17 10:22:52,801 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <== Total: 1
the student is : FemaleStudent [studentHealthFemaleList=[StudentHealthFemale [id=1, studentId=1, checkDate=2017-0615, heart=好, liver=好, spleen=好, lung=好, kidney=好, uterus=好, note=1号女学生健康检查表]]]
打印女学生健康检查信息: StudentHealthFemale [id=1, studentId=1, checkDate=2017-0615, heart=好, liver=好, spleen=好, lung=好, kidney=好, uterus=好, note=1号女学生健康检查表]
DEBUG 2017-06-17 10:22:52,802 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@79be0360]
DEBUG 2017-06-17 10:22:52,803 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@79be0360]
DEBUG 2017-06-17 10:22:52,803 org.apache.ibatis.datasource.pooled.PooledDataSource: Returned connection 2042495840 to pool.
从上面的日志可以看出,只执行了学生的sql获取学生信息,执行学生健康检查表的sql获取检查信息,学生证和学生成绩的sql没有执行,也就没调用,说明延迟加载了。但是注意这个延迟加载是按mybatis的默认的按层级加载的。
我们在修改测试代码,代码如下:
package org.mybatis.test;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.mapper.StudentMapper;
import org.mybatis.pojo.Student;
import org.mybatis.util.SqlSessionFactoryUtil;
public class MybatisMainTest5 {
public static void main(String[] args) {
// TODO Auto-generated method stub
SqlSession sqlSession = null;
try {
sqlSession = SqlSessionFactoryUtil.openSqlSession();
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
Student student = studentMapper.getStudent(1);
// 打印学生对象
System.out.println("the student is : " + student);
// StudentLecture studentLecture =
// student.getStudentLectureList().get(0);
// 打印成绩信息
// System.out.println("成绩信息:" + studentLecture);
// System.out.println("打印课程信息:" + studentLecture.getLecture());
// 判断是男性还是女性
/*
* if (student instanceof MaleStudent) { MaleStudent maleStudent =
* (MaleStudent) student; System.out.println("打印男学生健康检查信息: " +
* maleStudent.getStudentHealthMaleList().get(0)); } else {
* FemaleStudent maleStudent = (FemaleStudent) student;
* System.out.println("打印女学生健康检查信息: " +
* maleStudent.getStudentHealthFemaleList().get(0)); }
*/
} catch (Exception e) {
System.err.println(e.getMessage());
sqlSession.rollback();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
}
运行测试程序,日志如下:
DEBUG 2017-06-17 10:30:41,977 org.apache.ibatis.datasource.pooled.PooledDataSource: Created connection 2042495840.
DEBUG 2017-06-17 10:30:41,977 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@79be0360]
DEBUG 2017-06-17 10:30:41,979 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Preparing: select id,name,sex,card_no,note from t_student where id = ?
DEBUG 2017-06-17 10:30:42,010 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 1(Integer)
DEBUG 2017-06-17 10:30:42,120 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <== Total: 1
DEBUG 2017-06-17 10:30:42,122 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Preparing: select id,student_id,native_place,issue_date,end_date,note from t_student_card where student_id =?
DEBUG 2017-06-17 10:30:42,122 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 1(Integer)
DEBUG 2017-06-17 10:30:42,126 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <== Total: 1
DEBUG 2017-06-17 10:30:42,126 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Preparing: select id,student_id,lecture_id,grade,note from t_student_lecture where student_id = ?
DEBUG 2017-06-17 10:30:42,126 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 1(Integer)
DEBUG 2017-06-17 10:30:42,130 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <== Total: 1
DEBUG 2017-06-17 10:30:42,130 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Preparing: select id,student_id studentId,check_date checkDate,heart, liver,spleen,lung,kidney,uterus,note from t_student_health_female where student_id = ?
DEBUG 2017-06-17 10:30:42,131 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 1(Integer)
DEBUG 2017-06-17 10:30:42,137 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <== Total: 1
the student is : FemaleStudent [studentHealthFemaleList=[StudentHealthFemale [id=1, studentId=1, checkDate=2017-0615, heart=好, liver=好, spleen=好, lung=好, kidney=好, uterus=好, note=1号女学生健康检查表]]]
DEBUG 2017-06-17 10:30:42,137 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@79be0360]
DEBUG 2017-06-17 10:30:42,138 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@79be0360]
DEBUG 2017-06-17 10:30:42,138 org.apache.ibatis.datasource.pooled.PooledDataSource: Returned connection 2042495840 to pool.
注意看测试程序和日志,发现我只打印学生信息但是学生证,课程成绩,健康情况检查的sql都执行了,只缺一个课程没执行了。当我们加载学生信息时,它会根据鉴别器去找到健康的情况。
这个时候aggressiveLazyLoading就可以用了,当它为true时,mybatis的内容按层级加载,否则就按我们调用的要求加载。所以这时候我们修改下mybatis的配置文件,代码如下:
<?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="org/mybatis/config/database.properties" />
<settings>
<setting name="logImpl" value="LOG4J" />
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
<!-- 定义类的别名 -->
<typeAliases>
<typeAlias type="org.mybatis.pojo.Role" alias="role" />
</typeAliases>
<!-- 定义数据库信息,默认使用development数据库构建环境 -->
<environments default="development">
<environment id="development">
<!--采用jdbc事务管理 -->
<transactionManager type="JDBC">
<property name="autoCommit" value="false" />
</transactionManager>
<!-- 配置数据库连接信息 -->
<dataSource type="POOLED">
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/mapper/RoleMapper.xml" />
<mapper resource="org/mybatis/mapper/userMapper.xml" />
<mapper resource="org/mybatis/mapper/StudentMapper.xml" />
<mapper resource="org/mybatis/mapper/StudentCardMapper.xml" />
<mapper resource="org/mybatis/mapper/StudentLectureMapper.xml" />
<mapper resource="org/mybatis/mapper/LectureMapper.xml" />
<mapper resource="org/mybatis/mapper/MaleStudentMapper.xml" />
<mapper resource="org/mybatis/mapper/FemaleStudentMapper.xml" />
</mappers>
</configuration>
把aggressiveLazyLoading设置为false,这时候就可以达到按需加载了。
修改mybati的配置文件,设置的是全局的延迟加载,不能够指定哪些属性进行延迟加载。当然mybatis也提供了很人性化的属性,让我们可以指定属性进行延迟加载。我们可以在association和collection元素上加入属性值fetchType就可以了,它有两个取值,eager和lazy。一旦配置了它们,那么全局的变量就会被它们覆盖,这样我们就可以灵活的指定哪些东西可以立即加载,哪些可以延迟加载。
级联的优势就是能够方便快捷的获取数据。比如学生和学生成绩信息往往是最常用的级联信息,这个时候级联完全是有必要的,级联最好不要超过三层,多层级联会导致复杂性的增加,不利于理解和维护。同时级联也存在严重的问题,例如我只对学生课程和成绩感兴趣,就不用取出学生证和健康情况表了。因为取出学生证和健康表不但没有意义而且还会多执行sql,导致性能下降。
级联还有更严重的问题,假设表关联到Student表里面,那么可以想象,我们还要增加级联关系到这个结果集里,那么级联关系将会异常复杂。如果我们采取类似默认的场景那么有一个关联我们就要多执行一次sql,每次取出一个Student对象,那么它所有信息都会被取出来,这样造成sql执行过多,导致性能下降,这就是N+1问题,为了解决这个问题我们可以考虑延迟加载的功能。
二:延迟加载
为了处理N+1问题,mybatis引入了延迟加载的功能,延迟加载的意义在于一开始并不取出级联数据,只有当使用它了才发送sql去取回数据。
mybatis的配置中有两个全局的参数lazyLoadingEnabled和aggressiveLazyLoading。lazyLoadingEnable的含义是是否开启延迟加载功能。aggressiveLazyLoading的含义是对任意延迟属性的调用会使带有延迟加载属性的对象完整加载;反之每种属性按需加载。
mybatis默认情况都是及时加载的,现在修改mybatis配置问题settings元素里面的lazyLoadingEnabled值开启延迟加载,使得关联属性都按需加载,而不自动加载。
<?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="org/mybatis/config/database.properties" />
<settings>
<setting name="logImpl" value="LOG4J" />
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
<!-- 定义类的别名 -->
<typeAliases>
<typeAlias type="org.mybatis.pojo.Role" alias="role" />
</typeAliases>
<!-- 定义数据库信息,默认使用development数据库构建环境 -->
<environments default="development">
<environment id="development">
<!--采用jdbc事务管理 -->
<transactionManager type="JDBC">
<property name="autoCommit" value="false" />
</transactionManager>
<!-- 配置数据库连接信息 -->
<dataSource type="POOLED">
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/mapper/RoleMapper.xml" />
<mapper resource="org/mybatis/mapper/userMapper.xml" />
<mapper resource="org/mybatis/mapper/StudentMapper.xml" />
<mapper resource="org/mybatis/mapper/StudentCardMapper.xml" />
<mapper resource="org/mybatis/mapper/StudentLectureMapper.xml" />
<mapper resource="org/mybatis/mapper/LectureMapper.xml" />
<mapper resource="org/mybatis/mapper/MaleStudentMapper.xml" />
<mapper resource="org/mybatis/mapper/FemaleStudentMapper.xml" />
</mappers>
</configuration>
测试程序修改如下:
package org.mybatis.test;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.mapper.StudentMapper;
import org.mybatis.pojo.FemaleStudent;
import org.mybatis.pojo.MaleStudent;
import org.mybatis.pojo.Student;
import org.mybatis.util.SqlSessionFactoryUtil;
public class MybatisMainTest5 {
public static void main(String[] args) {
// TODO Auto-generated method stub
SqlSession sqlSession = null;
try {
sqlSession = SqlSessionFactoryUtil.openSqlSession();
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
Student student = studentMapper.getStudent(1);
// 打印学生对象
System.out.println("the student is : " + student);
// StudentLecture studentLecture =
// student.getStudentLectureList().get(0);
// 打印成绩信息
// System.out.println("成绩信息:" + studentLecture);
// System.out.println("打印课程信息:" + studentLecture.getLecture());
// 判断是男性还是女性
if (student instanceof MaleStudent) {
MaleStudent maleStudent = (MaleStudent) student;
System.out.println("打印男学生健康检查信息: " + maleStudent.getStudentHealthMaleList().get(0));
} else {
FemaleStudent maleStudent = (FemaleStudent) student;
System.out.println("打印女学生健康检查信息: " + maleStudent.getStudentHealthFemaleList().get(0));
}
} catch (Exception e) {
System.err.println(e.getMessage());
sqlSession.rollback();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
}
测试结果如下:
org.apache.ibatis.transaction.jdbc.JdbcTransaction: Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@79be0360]
DEBUG 2017-06-17 10:22:52,587 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Preparing: select id,name,sex,card_no,note from t_student where id = ?
DEBUG 2017-06-17 10:22:52,622 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 1(Integer)
DEBUG 2017-06-17 10:22:52,748 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <== Total: 1
DEBUG 2017-06-17 10:22:52,748 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Preparing: select id,student_id,native_place,issue_date,end_date,note from t_student_card where student_id =?
DEBUG 2017-06-17 10:22:52,749 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 1(Integer)
DEBUG 2017-06-17 10:22:52,751 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <== Total: 1
DEBUG 2017-06-17 10:22:52,751 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Preparing: select id,student_id,lecture_id,grade,note from t_student_lecture where student_id = ?
DEBUG 2017-06-17 10:22:52,751 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 1(Integer)
DEBUG 2017-06-17 10:22:52,757 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <== Total: 1
DEBUG 2017-06-17 10:22:52,757 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Preparing: select id,student_id studentId,check_date checkDate,heart, liver,spleen,lung,kidney,uterus,note from t_student_health_female where student_id = ?
DEBUG 2017-06-17 10:22:52,757 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 1(Integer)
DEBUG 2017-06-17 10:22:52,801 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <== Total: 1
the student is : FemaleStudent [studentHealthFemaleList=[StudentHealthFemale [id=1, studentId=1, checkDate=2017-0615, heart=好, liver=好, spleen=好, lung=好, kidney=好, uterus=好, note=1号女学生健康检查表]]]
打印女学生健康检查信息: StudentHealthFemale [id=1, studentId=1, checkDate=2017-0615, heart=好, liver=好, spleen=好, lung=好, kidney=好, uterus=好, note=1号女学生健康检查表]
DEBUG 2017-06-17 10:22:52,802 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@79be0360]
DEBUG 2017-06-17 10:22:52,803 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@79be0360]
DEBUG 2017-06-17 10:22:52,803 org.apache.ibatis.datasource.pooled.PooledDataSource: Returned connection 2042495840 to pool.
从上面的日志可以看出,只执行了学生的sql获取学生信息,执行学生健康检查表的sql获取检查信息,学生证和学生成绩的sql没有执行,也就没调用,说明延迟加载了。但是注意这个延迟加载是按mybatis的默认的按层级加载的。
我们在修改测试代码,代码如下:
package org.mybatis.test;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.mapper.StudentMapper;
import org.mybatis.pojo.Student;
import org.mybatis.util.SqlSessionFactoryUtil;
public class MybatisMainTest5 {
public static void main(String[] args) {
// TODO Auto-generated method stub
SqlSession sqlSession = null;
try {
sqlSession = SqlSessionFactoryUtil.openSqlSession();
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
Student student = studentMapper.getStudent(1);
// 打印学生对象
System.out.println("the student is : " + student);
// StudentLecture studentLecture =
// student.getStudentLectureList().get(0);
// 打印成绩信息
// System.out.println("成绩信息:" + studentLecture);
// System.out.println("打印课程信息:" + studentLecture.getLecture());
// 判断是男性还是女性
/*
* if (student instanceof MaleStudent) { MaleStudent maleStudent =
* (MaleStudent) student; System.out.println("打印男学生健康检查信息: " +
* maleStudent.getStudentHealthMaleList().get(0)); } else {
* FemaleStudent maleStudent = (FemaleStudent) student;
* System.out.println("打印女学生健康检查信息: " +
* maleStudent.getStudentHealthFemaleList().get(0)); }
*/
} catch (Exception e) {
System.err.println(e.getMessage());
sqlSession.rollback();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
}
运行测试程序,日志如下:
DEBUG 2017-06-17 10:30:41,977 org.apache.ibatis.datasource.pooled.PooledDataSource: Created connection 2042495840.
DEBUG 2017-06-17 10:30:41,977 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@79be0360]
DEBUG 2017-06-17 10:30:41,979 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Preparing: select id,name,sex,card_no,note from t_student where id = ?
DEBUG 2017-06-17 10:30:42,010 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 1(Integer)
DEBUG 2017-06-17 10:30:42,120 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <== Total: 1
DEBUG 2017-06-17 10:30:42,122 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Preparing: select id,student_id,native_place,issue_date,end_date,note from t_student_card where student_id =?
DEBUG 2017-06-17 10:30:42,122 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 1(Integer)
DEBUG 2017-06-17 10:30:42,126 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <== Total: 1
DEBUG 2017-06-17 10:30:42,126 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Preparing: select id,student_id,lecture_id,grade,note from t_student_lecture where student_id = ?
DEBUG 2017-06-17 10:30:42,126 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 1(Integer)
DEBUG 2017-06-17 10:30:42,130 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <== Total: 1
DEBUG 2017-06-17 10:30:42,130 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Preparing: select id,student_id studentId,check_date checkDate,heart, liver,spleen,lung,kidney,uterus,note from t_student_health_female where student_id = ?
DEBUG 2017-06-17 10:30:42,131 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 1(Integer)
DEBUG 2017-06-17 10:30:42,137 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <== Total: 1
the student is : FemaleStudent [studentHealthFemaleList=[StudentHealthFemale [id=1, studentId=1, checkDate=2017-0615, heart=好, liver=好, spleen=好, lung=好, kidney=好, uterus=好, note=1号女学生健康检查表]]]
DEBUG 2017-06-17 10:30:42,137 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@79be0360]
DEBUG 2017-06-17 10:30:42,138 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@79be0360]
DEBUG 2017-06-17 10:30:42,138 org.apache.ibatis.datasource.pooled.PooledDataSource: Returned connection 2042495840 to pool.
注意看测试程序和日志,发现我只打印学生信息但是学生证,课程成绩,健康情况检查的sql都执行了,只缺一个课程没执行了。当我们加载学生信息时,它会根据鉴别器去找到健康的情况。
这个时候aggressiveLazyLoading就可以用了,当它为true时,mybatis的内容按层级加载,否则就按我们调用的要求加载。所以这时候我们修改下mybatis的配置文件,代码如下:
<?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="org/mybatis/config/database.properties" />
<settings>
<setting name="logImpl" value="LOG4J" />
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
<!-- 定义类的别名 -->
<typeAliases>
<typeAlias type="org.mybatis.pojo.Role" alias="role" />
</typeAliases>
<!-- 定义数据库信息,默认使用development数据库构建环境 -->
<environments default="development">
<environment id="development">
<!--采用jdbc事务管理 -->
<transactionManager type="JDBC">
<property name="autoCommit" value="false" />
</transactionManager>
<!-- 配置数据库连接信息 -->
<dataSource type="POOLED">
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/mapper/RoleMapper.xml" />
<mapper resource="org/mybatis/mapper/userMapper.xml" />
<mapper resource="org/mybatis/mapper/StudentMapper.xml" />
<mapper resource="org/mybatis/mapper/StudentCardMapper.xml" />
<mapper resource="org/mybatis/mapper/StudentLectureMapper.xml" />
<mapper resource="org/mybatis/mapper/LectureMapper.xml" />
<mapper resource="org/mybatis/mapper/MaleStudentMapper.xml" />
<mapper resource="org/mybatis/mapper/FemaleStudentMapper.xml" />
</mappers>
</configuration>
把aggressiveLazyLoading设置为false,这时候就可以达到按需加载了。
修改mybati的配置文件,设置的是全局的延迟加载,不能够指定哪些属性进行延迟加载。当然mybatis也提供了很人性化的属性,让我们可以指定属性进行延迟加载。我们可以在association和collection元素上加入属性值fetchType就可以了,它有两个取值,eager和lazy。一旦配置了它们,那么全局的变量就会被它们覆盖,这样我们就可以灵活的指定哪些东西可以立即加载,哪些可以延迟加载。
相关文章推荐
- mybatis的一对一,一对多的关系映射配置及性能分析(延迟加载)
- 深入Hibernate的映射文件---5.6.5: 集合属性的性能分析
- mybatis ---- 级联查询 一对多 (集合映射)
- mybatis ---- 级联查询 一对多 (集合映射)mybatis中:returned more than one row, where no more than one was expected
- MyBatis 源码分析 - 映射文件解析过程
- 语义层设计之多表级联的性能分析
- MyBatis中Mapper接口映射到数据库原理分析
- mybatis ---- 级联查询 一对多 (集合映射)
- Mybatis源码分析之参数映射及处理ParameterHandler
- Mybatis源码分析之参数映射及处理ParameterHandler
- mybatis级联映射
- MyBatis 源码分析——映射结果
- mybatis ---- 级联查询 一对多 (集合映射)
- mybatis -spring 集成映射原理 --分析
- Mybatis3.4.x技术内幕(二十一):参数设置、结果封装、级联查询、延迟加载原理分析
- mybatis源码学习之执行过程分析(2)——config.xml配置文件和mapper.xml映射文件解析过程
- mybatis进阶(1)--高级映射之数据模型分析
- mybatis ---- 级联查询 一对多 (集合映射)
- Mybatis - 高级映射 (复习,数据表分析,一对一 之 resultType )
- mybatis源码学习之执行过程分析(4)——映射文件中sql的获取和sql语句的执行