MyBatis级联第五篇——树形加载规则和非全局性加载,延迟加载原理(推荐,继续上篇的重要原创)
来源:互联网 发布:富士康工资知乎 编辑:程序博客网 时间:2024/05/21 10:21
到了级联最后的章节,上次中我们讨论了延迟加载,但是最后有点凌乱,估计大家摸不着头脑,希望大家hold住,这里我们再升华为理论知识,就十分简单了。
1、树形层级加载:
上篇,我们将全局参数变为:
<setting name="lazyLoadingEnabled" value="true"/> <setting name="aggressiveLazyLoading" value="true"/>
我们发现其延迟加载规则,貌似不可触摸,于是大家都很懵懂,不过不要紧我们我们回到第一篇
MyBatis级联探讨第一篇——概念和模型
的模型图,我们可以得到这样的一张树形图:
有了这个图,这样就方便论述了,
加载员工的时候,MyBatis会把员工和鉴别器,健康情况当做树形的第一层级加载,所以运行了2个SQL。
我们通过延迟加载员工卡信息的时候,因为负责项目信息和员工卡是同一个层级,所以MyBatis会连同该员工负责的项目也同时加载进来。
这便是MyBatis的树形加载。
2、非全局定义延迟加载策略:
在很多情况下,作为公司的管理层,往往对员工卡不感兴趣,而对其负责的项目情况则十分感兴趣,因此我们需要这样的一个场景,在加载员工信息的时候,顺便连同把其负责的项目信息也加载进来,而不需要把员工卡和健康情况这些信息加载进来。
但是按上篇要么全部延迟加载要么全部延迟加载,再或者是按树形加载。但是不要紧,mybatis为我们提供了可以非全局配置的延迟加载功能,让我们学习它们。
在关联的元素(association ,collection ,discriminator)中,我们存在一个属性:fetchType来决定是否需要延迟加载,如果配置它,它将覆盖掉原有在MyBatis设置的策略。
对于它而言,它有两个取值:
- lazy: 延迟加载
- eager:即刻加载
由它来决定是否需要延迟或者即刻加载。
这样让我们修改Mapper的配置,来保证加载员工信息的同事即刻加载项目信息,同时不要加载其他的信息,我们先把xml的配置修改过来:
<settings> <setting name="cacheEnabled" value="true"/> <setting name="lazyLoadingEnabled" value="true"/> <setting name="aggressiveLazyLoading" value="false"/> </settings>
然后加入如下的配置:
<?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.ykzhen2015.csdn.mapper.EmployeeMapper"><resultMap id="employeeMap" type="com.ykzhen2015.csdn.pojo.Employee"><id property="id" column="id" /><result property="empName" column="emp_name" /><result property="sex" column="sex" /><association property="employeeCard" column="id" fetchType="lazy"select="com.ykzhen2015.csdn.mapper.EmployeeCardMapper.getEmployeeCardByEmpId" /><collection property="projectList" column="id" fetchType="eager"select="com.ykzhen2015.csdn.mapper.ProjectMapper.findProjectByEmpId" /><discriminator javaType="int" column="sex"><case value="1" resultMap="maleEmployeeMap" /><case value="2" resultMap="femaleEmployeeMap" /></discriminator></resultMap><select id="getEmployee" parameterType="int" resultMap="employeeMap">select id, emp_name as empName, sex from t_employee where id =#{id}</select><resultMap id="maleEmployeeMap" type="com.ykzhen2015.csdn.pojo.MaleEmployee" extends="employeeMap"><collection fetchType="lazy" property="prostateList" select="com.ykzhen2015.csdn.mapper.MaleEmployeeMapper.findProstateList" column="id" /></resultMap><resultMap id="femaleEmployeeMap" type="com.ykzhen2015.csdn.pojo.FemaleEmployee" extends="employeeMap"><collection fetchType="lazy" property="uterusList" select="com.ykzhen2015.csdn.mapper.FemaleEmployeeMapper.findUterusList" column="id" /></resultMap></mapper>
请注意,关联的元素(association ,collection ,discriminator)中的fetchType属性,它的范围是:eager和lazy。我们这里将取员工卡和健康情况的设置为lazy,意味着它将延迟加载,把获取项目情况的设置为eager,意味着加载员工信息后,就会加载项目情况,好让我们再次运行程序,
public static void main(String []args) {SqlSession sqlSession = null;try {sqlSession = SqlSessionFactoryUtil.openSqlSession();EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);Employee emp = employeeMapper.getEmployee(1);} finally {if (sqlSession != null) { sqlSession.close();}}}
可以得到如下日志:
DEBUG 2016-05-16 14:15:54,793 org.apache.ibatis.logging.LogFactory: Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter.DEBUG 2016-05-16 14:15:54,883 org.apache.ibatis.datasource.pooled.PooledDataSource: PooledDataSource forcefully closed/removed all connections.DEBUG 2016-05-16 14:15:54,883 org.apache.ibatis.datasource.pooled.PooledDataSource: PooledDataSource forcefully closed/removed all connections.DEBUG 2016-05-16 14:15:54,883 org.apache.ibatis.datasource.pooled.PooledDataSource: PooledDataSource forcefully closed/removed all connections.DEBUG 2016-05-16 14:15:54,883 org.apache.ibatis.datasource.pooled.PooledDataSource: PooledDataSource forcefully closed/removed all connections.DEBUG 2016-05-16 14:15:54,883 org.apache.ibatis.datasource.pooled.PooledDataSource: PooledDataSource forcefully closed/removed all connections.DEBUG 2016-05-16 14:15:54,993 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Opening JDBC ConnectionDEBUG 2016-05-16 14:15:55,227 org.apache.ibatis.datasource.pooled.PooledDataSource: Created connection 1037324811.DEBUG 2016-05-16 14:15:55,227 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Preparing: select id, emp_name as empName, sex from t_employee where id =? DEBUG 2016-05-16 14:15:55,259 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 1(Integer)DEBUG 2016-05-16 14:15:55,347 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ====> Preparing: SELECT a.id, a.proj_name as projName FROM t_project a, t_employee_project b where a.id = b.proj_id and b.emp_id = ? DEBUG 2016-05-16 14:15:55,347 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ====> Parameters: 1(Integer)DEBUG 2016-05-16 14:15:55,347 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <==== Total: 2DEBUG 2016-05-16 14:15:55,347 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <== Total: 1DEBUG 2016-05-16 14:15:55,347 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@3dd4520b]DEBUG 2016-05-16 14:15:55,347 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@3dd4520b]DEBUG 2016-05-16 14:15:55,347 org.apache.ibatis.datasource.pooled.PooledDataSource: Returned connection 1037324811 to pool.
好,它打印了我们运行的轨迹,正是我们所需要的,在加载员工信息后,它会马上加载项目信息,而对于其他的一律都不予加载,通过fetchType属性,我们可以自定义那些可以加载,那些不加载,这样就可以很灵活的处理级联的延迟加载问题。
3、延迟加载的设计原理
延迟加载是使用动态代理来实现的,关于动态代理可以看到我的文章:
MyBATIS插件原理第一篇——技术基础(反射和JDK动态代理)
我们拿员工信息和员工卡信息作为例子谈谈,延迟加载。当我们获取了员工的信息,此时,我们生成一个员工卡的代理对象,而这个对象只是记录一些关键的关联字段,而没有发送SQL去把员工卡的信息拿出来,当我们调用员工卡的信息的时候,它就会进入动态代理的invoke方法,在访问信息前,通过SQL和记录的关联信息找到数据库的信息进行回填,这便是延迟加载的原理。
在MyBatis中,如果是在3.3.0版本(不含)以下,采用的是CGLib动态代理,以上(含)采用的是JAVASSIST。有关它们的研究可以参考别的书籍。
4、总结
好了,所有的我们都谈完了,都是笔者自己经过多次研究和反复的结果,如果有误欢迎指正,学到知识的,要感谢博主哦,写这些真的不是那么简单的,希望大家能够掌握MyBatis的级联哦。
- MyBatis级联第五篇——树形加载规则和非全局性加载,延迟加载原理(推荐,继续上篇的重要原创)
- MyBatis级联第四篇——N+1问题和全局延迟加载【推荐,MyBatis级联重要的一篇原创,建议认真读】
- mybatis的延迟加载 (懒加载)
- mybatis——延迟加载
- MyBatis——【延迟加载】
- Mybatis的延迟加载
- mybatis的延迟加载
- Mybatis的延迟加载
- mybatis的延迟加载
- mybatis 的延迟加载
- Mybatis的延迟加载
- Mybatis的延迟加载
- mybatis--()延迟加载
- MyBatis延迟加载,分层加载和局部延迟加载
- mybatis的延迟加载和一、二级缓存
- mybatis缓存和延迟加载
- mybatis延迟加载(懒加载)
- 动态树形多选菜单——ztree初始化加载和延迟加载
- 六个技巧,培养孩子乐观心态
- 指向学生类的指针
- 292. Nim Game [easy] (Python)
- javascript:history.go()和History.back()的区别及应用
- lintcode----二叉树的所有路径
- MyBatis级联第五篇——树形加载规则和非全局性加载,延迟加载原理(推荐,继续上篇的重要原创)
- Codeforces Round #191 (Div. 2) C. Magic Five
- 第十一周实践项目(5)——a
- OrmLite数据库框架的集成及使用
- 怎么阻止直接输入地址访问 html 页面
- nyoj 973 天下第一
- 深刻复制 1
- 最强ListView优化方案
- (五)主从复制