1.引子

mybatis的延迟加载,主要应用于一个实体类中有复杂数据类型的属性,包括一对一和一对多的关系(在xml中用collection、association标签标识)。这个种属性往往还对应着另一个数据表,而实际查询的需求不一定需要这个的表的数据,那么此时延迟加载相对于连表查询就有很大的优势,达到了按需加载的目的。这对提高访问速度和降低系统资源耗费有着很大的意义。

2.连表查询

背景: 用户实体类User中包含有一个为角色实体类Role类型的属性role,及对应角色表主键id的roleUser整型属性

需求:用角色id和用户id列表,查找出用户信息,及其所角色名称

分析: 角色名称不在用户表中,用户表中只有角色表的主键id,那么此就必须要根据roleUser到角色表中再查询。为了减少查询次数,实际上我们进行连表查询。

实体类User中的部分属性

   private Integer id; // id
private String userCode; // 用户编码
private String userName; // 用户名称
private String userPassword; // 用户密码
private Integer userRole; // 用户角色id,和角色表smbms_role的id字段关联对应
private Role role; //角色 一对一 对应关系
private List<Address> addressList; //地址 一对多

实体类Role中的属性

  private Integer id; // id
private String roleCode; // 角色编码
private String roleName; // 角色名称
private Integer createdBy; // 创建者
private Date creationDate; // 创建时间
private Integer modifyBy; // 更新者
private Date modifyDate;// 更新时间

xml中的sql语句映射文件

<!-- 演示 一对一 association 的连表查询 start -->

    <resultMap type="Role" id="roleMap">
<id property="id" column="r_id" />
<result property="roleCode" column="roleCode" />
<result property="roleName" column="roleName" />
</resultMap>
<resultMap type="User" id="userRoleResult">
<id property="id" column="id" />
<result property="userCode" column="userCode" />
<result property="userName" column="userName" />
<association property="role" javaType="Role" resultMap="roleMap" />
</resultMap>
<!-- 根据用户表中角色id 和角色表做联表查询 -->
<select id="getUserListByRoleId" parameterType="int" resultMap="userRoleResult">
select u.* ,r.id as r_id,r.roleCode,r.roleName from
smbms_user
u,smbms_role r
where u.userRole = #{userRoleId} and u.userRole = r.id
</select> <!-- 演示 一对一 association 的连表查询 end -->

测试方法

  @Test
public void selectUserByIdsAndRoleId()
{
List<User> users = sqlSession.getMapper(UserMapper.class).selectUserByIdsAndRoleId(3, Arrays.asList(4, 3, 7,12));
for (User userElement : users)
{
System.out.println(userElement);
}
}

3. 延迟加载

1)延迟加载配置

延迟加载可以在主配置文件mybatis-config.xml中配置,在这里的配置是全局配置,默认对所有查询SQL进行延迟加载处理。

<settings>
<!--启用延迟加载 -->
<setting name="lazyLoadingEnabled" value="true" />
<!--关闭积极加载 -->
<setting name="aggressiveLazyLoading" value="false" />
</settings>

另外如果对全局配置不满意,可以在具体的SQL映射语句中添加collect或assocation标签中添加属性fetchType="lazy"(延迟加载)或fetchType="eager"(立即加载),

此处SQL加载方式将覆盖全局配置中的SQL加载方式,如伪代码

<collection property="addressList"
ofType="Address" column="id"
fetchType="lazy|eager"/>

2)延迟加载SQL映射

背景: 用户实体类User中包含有一个List集合且元素类型为Address的属性addressList,用户表的id与地址表的userId有对应的主外键关系

需求:使用用户id查找出用户信息及相关地址信息(但地址可能不会总是被使用)

分析: 地址信息不总会用到,如果某次查询刚好是这种情况,也就没有必要再去查询地址表了。这时就可以使用延迟加载技术,实现按需动态加载资源。

xml中的sql映射代码

    <!--演示 一对多 collection -->
<resultMap type="User" id="userAddressResult">
<id property="id" column="id" />
<result property="userCode" column="userCode" />
<result property="phone" column="phone" />
<result property="userName" column="userName" />
<!-- 在collection标签内需要注意这几个属性的设置
1."column"属性,此属性是两张表关联的关键,此字段的值能唯一确定另一张从表的对应记录行,此字段与从表的外键一一对应,此字段一般为主表的主键,
相当于连表查询中根据主外键建立两张的的关联关系,
如" from smbms_user u inner join smbms_address a on u.id = a.userId "
2."select"属性,此属性指定可能需要查询SQL的id,
3."fetchType"属性,指定为"lazy"(懒加载)实现延迟加载效果(若全局配置已配置过延迟加载,也可在此处不写此属性,
mybatis也会默认读到全局配置中的延迟加载项),而"eager"表示立即加载
4.ofType可以不写,lazyFindAddressListByUserId这个查询本身已经指定了返回数据类型
-->
<collection property="addressList" ofType="Address" column="id"
select="lazyFindAddressListByUserId" fetchType="lazy" />
</resultMap> <!-- 延迟按需加载sql语句(即此sql可能不会使用) -->
<select id="lazyFindAddressListByUserId" parameterType="int"
resultType="Address">
<!-- 如果确实需要此SQL查询,则上面<collection>标签中的"column='id'"
的id字段的对应值将传到此处的'userId=#{id}'中作为参数 ,进一步查询地址表smbms_address
-->
<!-- 若此处SQL确实被执行了,那么就相当于连表查询语句
select a.* ,u.* from
smbms_user u inner join smbms_address a on u.id = a.userId and u.id = #{id}
-->
select * from smbms_address where userId=#{id}
</select> <!-- 根据用户id获得 用户信息及多个地址信息 -->
<select id="getAddressListByUserId" parameterType="Integer"
resultMap="userAddressResult">
select * from smbms_user where id = #{userId}
</select>

3)延迟加载测试

不使用addressList地址信息的测试方法

 @Test
public void getAddressListByUserId()
{
List<User> users = sqlSession.getMapper(UserMapper.class).getAddressListByUserId(5);
for (User userElement : users)
{
//不使用addressList属性
System.out.println(userElement.getPhone() +" "+userElement.getUserCode());
// System.out.println(userElement);
}
}

控制台显示只有一个sql语句,则实际上只查询了一张用户表

使用addressList地址信息的测试方法

 @Test
public void getAddressListByUserId()
{
List<User> users = sqlSession.getMapper(UserMapper.class).getAddressListByUserId(5);
for (User userElement : users)
{
// 使用addressList属性
// System.out.println(userElement.getPhone() +" "+userElement.getUserCode());
System.out.println(userElement);
}
}

控制台显示只有两条sql语句,则实际上只先查询了用户表,再用用户id去查询地址表

4.总结

(1)连表查询,在任何情况下都要同时查询多张表的数据 ;  而延迟加载,只有在项目中确实使用到了另一个从表的数据,才会去查询第二(N)张表的数据。

(2)连表查询同时操作多张表,如果多张表的字段名有相同的,为了正确的将字段值映射到实体类的属性上,可能要给相同的字段名取一个别名,并对结果集进行相应的自定义映射;

而延迟加载相当于将一次连表查询操作分解为多次单表查询操作,既然是单表操作也就不可能出现字段名相同的情况,只要数据表的字段名和实体类的属性名按照同样的驼峰命名规则,就不需要对结果集进行自定义映射(mybatis会做默认的结果集映射)。

(3)对实体类的复杂数据类型属性做SQL映射,两者都会使用到"association"或"collection"标签。而连表查询、延迟加载在"association"或"collection"标签中的属性设置有些区别,延迟加载特别的要使用"column"、"select"、"fetchType"这三个属性。连表查询只能解决一对一的级联关系,而延迟加载既能处理一对一的级联,也能解决一对多的级联查询问题。

在mybatis框架中,延迟加载与连表查询的差异的更多相关文章

  1. 详解Java的MyBatis框架中SQL语句映射部分的编写

    这篇文章主要介绍了Java的MyBatis框架中SQL语句映射部分的编写,文中分为resultMap和增删查改实现两个部分来讲解,需要的朋友可以参考下 1.resultMap SQL 映射XML 文件 ...

  2. mybatis框架中XxxxMaper.xml的文件

    我们知道在mybatis框架中,config.xml中会关联到许多的XxxxMapper的xml文件,这些文件又对应着一个个的接口,来观察下这些xml文件 从以下这个文件为例子: <?xml v ...

  3. Mybatis 一对多延迟加载,并且子查询中与主表字段不对应 (19)

    Mybatis  一对多延迟加载,并且子查询中与主表字段不对应应用说明. 实现一对多关联(懒加载),一个教研组对应多个教师,既:教师的教研编号与教研组的教研编号关联,并且教师关联教研组外键与教研组编号 ...

  4. Mybatis框架中实现双向一对多关系映射

    学习过Hibernate框架的伙伴们很容易就能简单的配置各种映射关系(Hibernate框架的映射关系在我的blogs中也有详细的讲解),但是在Mybatis框架中我们又如何去实现 一对多的关系映射呢 ...

  5. mybatis逆向工程,实现join多表查询,避免多表相同字段名的陷阱

    ​ mybatis逆向工程,实现join多表查询,避免多表相同字段名的陷阱 ​ 前言:使用 mybatis generator 生成表格对应的pojo.dao.mapper,以及对应的example的 ...

  6. Oracle中把一张表查询结果插入到另一张表中

      1. 新增一个表,通过另一个表的结构和数据 create table XTHAME.tab1 as select * from DSKNOW.COMBDVERSION 2. 如果表存在: inse ...

  7. Spring+MyBatis框架中sql语句的书写,数据集的传递以及多表关联查询

    在很多Java EE项目中,Spring+MyBatis框架经常被用到,项目搭建在这里不再赘述,现在要将的是如何在项目中书写,增删改查的语句,如何操作数据库,以及后台如何获取数据,如何进行关联查询,以 ...

  8. 【mybatis】使用mybatis框架中踩过的坑

    好久没来记录一下自己的学习情况,最近都在学框架,今天来记录一下关于mybatis框架的学习过程中碰过的一些问题: 以下内容可能稍微有点凌乱,因为是把之前遇到过的错误或异常都集中一起了,不过我已经把问题 ...

  9. 优化mybatis框架中的查询用户记录数的案例

    通过对mybatis框架的中核心接口和类的分析,发现之前写的那个小demo是有问题的.现在对其进行部分优化. 如果存在多个功能的时候,势必会有很多重复的代码,如,创建sqlsession对象,关闭sq ...

随机推荐

  1. oracle 使用触发器实现id自增

    前提:存在数据库di_test,主键为id.1.创建一个索引sequence create sequence di_test_id minvalue 1 nomaxvalue start with 1 ...

  2. Python 加载mnist、cifar数据

    import tensorflow.examples.tutorials.mnist.input_data mnist = input_data.read_data_sets("MNIST_ ...

  3. ACM-售货员难题

    题目描述:售货员的难题  某乡有n个村庄(1< n < 20),有一个售货员,他要到各个村庄去售货,各村庄之间的路程s(0 < s < 1000)是已知的,且A村到B村与B村到 ...

  4. DW1000芯片定位技术解析

    近些年来随着物联网和机器人技术的大发展,精确定位技术的热度也随之攀升.目前精确定位的技术有很多,如基于wifi.RFID.zigbee.超声波.UWB等技术都可以实现精准定位.由于技术的不同,精度也不 ...

  5. 【LeetCode】电话号码的字母组合

    [问题]给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合. 给出数字到字母的映射如下(与电话按键相同).注意 1 不对应任何字母. 示例: 输入:" 输出:["ad ...

  6. 【LeetCode】最长公共子序列

    [问题]给定两个字符串A和B,长度分别为m和n,要求找出它们最长的公共子串,并返回其长度.例如:A = "HelloWorld"B = "loop"则A与B的最 ...

  7. 3 react 简书 添加 头部搜索动态效果

    1. 添加动态效果组件 yarn add react-transition-group 2. 修改 src/common/header/index.js import React, {Componen ...

  8. 【分类问题中模型的性能度量(二)】超强整理,超详细解析,一文彻底搞懂ROC、AUC

    文章目录 1.背景 2.ROC曲线 2.1 ROC名称溯源(选看) 2.2 ROC曲线的绘制 3.AUC(Area Under ROC Curve) 3.1 AUC来历 3.2 AUC几何意义 3.3 ...

  9. 【转】modelBuilder.Configurations.AddFromAssembly in EF Core

    EntityFramework 6.x protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnMode ...

  10. caffe + ssd网络训练过程

    參考博客:https://blog.csdn.net/xiao_lxl/article/details/79106837 1获取源代码:git clone https://github.com/wei ...