MyBatis学习——分步查询与延迟加载
声明:面试是遇到延迟加载问题,在网页搜索到此篇文章,感觉很有帮助,留此学习之用!
一、分步查询
分步查询通常应用于关联表查询,如:电商平台,查询订单信息时需要查询部分的用户信息;OA系统查询个人信息时需要查询部门信息,反之亦是。相对于关联查询来说,分步查询将查询sql拆分,这里引申出一个问题是:分步查询与关联表查询的不同。
从代码层面来说:关联表查询能够有效的简化代码编写逻辑,减小代码编写难度,同时避免B-U-G(代码多了,bug 就多了);
而分步查询则能够增强代码的可用性(这点我也不是非常理解,在实际开发中也未遇到过)
从功能上说:关联表查询毕竟只需要查询一次数据库,对于业务量较小的系统来说,效率更高,数据库压 力相对较小;
分步查询虽然需要多次查询数据,但是这也意味着能够更好地使用数据缓存服务,且缓存的 数据耦合度低,利用率高,而且单次查询效率很高,数据库压力较小(对于业务量较大的系 统来说)。还有一点则是数据库锁的问题,毕竟关联查询是多表同时使用,分步查询每次只 操作一个表。
分步查询的实现(以简单的OA系统为例)
业务场景一:嵌套标签association的应用---查询员工信息时,获取员工所在的部门信息。
1.建立员工与部门实体类
/*** 员工实体类* * @author xuyong**/
public class Employee {private Integer id;private String lastName;private String gender;private String email;private Department department;private Integer dId;public Integer getdId() {return dId;}public void setdId(Integer dId) {this.dId = dId;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getLastName() {return lastName;}public void setLastName(String lastName) {this.lastName = lastName;}public String getGender() {return gender;}public void setGender(String gender) {this.gender = gender;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}public Department getDepartment() {return department;}public void setDepartment(Department department) {this.department = department;}@Overridepublic String toString() {return "Employee [dId=" + dId + ", department=" + department+ ", email=" + email + ", gender=" + gender + ", id=" + id+ ", lastName=" + lastName + "]";}
}
/*** 部门实体类* * @author xuyong**/
public class Department {private Integer id;private String departmentName;private List<Employee> employee;public List<Employee> getEmployee() {return employee;}public void setEmployee(List<Employee> employee) {this.employee = employee;}/*** */private Department() {super();// TODO Auto-generated constructor stub}/*** @param id* @param departmentName*/private Department(Integer id, String departmentName) {super();this.id = id;this.departmentName = departmentName;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getDepartmentName() {return departmentName;}public void setDepartmentName(String departmentName) {this.departmentName = departmentName;}@Overridepublic String toString() {return "Department [departmentName=" + departmentName + ", employee="+ employee + ", id=" + id + "]";}}
2.JUNIT单元测试编写
获取sqlSession实例(未使用框架,自己手动获取)
/*** 获取sqlSession实例* @return* @throws IOException*/public SqlSessionFactory getSessionFactory() throws IOException {String resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);return new SqlSessionFactoryBuilder().build(inputStream);}
业务方法
/*** 分布查询实现:* 获取员工信息及部门信息* @throws IOException*/@Testpublic void test08() throws IOException {SqlSessionFactory sessionFactory = getSessionFactory();SqlSession sqlSession = sessionFactory.openSession();try {EmployeeDaoPlus dao = sqlSession.getMapper(EmployeeDaoPlus.class);Employee employee = dao.getEmpByIdStep(1);System.out.println(employee);} catch (Exception e) {e.printStackTrace();} finally {sqlSession.close();}}
在Mapper中定义接口
/*** 员工类Mapper接口* * @author xuyong**/
public interface EmployeeDaoPlus {/*** 分步查询测试* 获取员工信息同时获取部门信息* @param id* @return*/Employee getEmpByIdStep(Integer id);}
编写对应的XML(sql资源文件)文件
<!-- 使用association分布查询 --><select id="getEmpByIdStep" resultMap="MyEmpByStep">select * from employee where id=#{id}</select>
以下为查询结果,可以看到打印了两次sql
[com.xuyong.dao.EmployeeDaoPlus.getEmpByIdStep]-==> Preparing: select * from employee where id=? [com.xuyong.dao.EmployeeDaoPlus.getEmpByIdStep]-==> Parameters: 1(Integer)[com.xuyong.dao.EmployeeDaoPlus.getEmpByIdStep]-<== Columns: id, last_name, gender, email, d_id[com.xuyong.dao.EmployeeDaoPlus.getEmpByIdStep]-<== Row: 1, 徐永, 男, t1heluosh1@163.com, 1[com.xuyong.dao.DepartmentDao.getDepartmentById]-====> Preparing: select id,department_name from department where id=? [com.xuyong.dao.DepartmentDao.getDepartmentById]-====> Parameters: 1(Integer)[com.xuyong.dao.DepartmentDao.getDepartmentById]-<==== Columns: id, department_name[com.xuyong.dao.DepartmentDao.getDepartmentById]-<==== Row: 1, 文案部[com.xuyong.dao.DepartmentDao.getDepartmentById]-<==== Total: 1[com.xuyong.dao.EmployeeDaoPlus.getEmpByIdStep]-<== Total: 1Employee [dId=1, department=Department [departmentName=文案部, employee=null, id=1], email=t1heluosh1@163.com, gender=男, id=1, lastName=徐永]
业务场景二:嵌套标签collection的应用---查询部门信息时,获取该部门下所有的员工。
collection主要用于映射集合数据,工作中常见的应用场景有:
订单查询、地址查询、产品分类查询
Junit单元测试
/*** 分步查询* 查询部门时获取部门里所有的员工信息* * @throws IOException*/@Testpublic void test10() throws IOException {SqlSessionFactory sessionFactory = getSessionFactory();SqlSession sqlSession = sessionFactory.openSession();try {DepartmentDao dao = sqlSession.getMapper(DepartmentDao.class);Department department = dao.getDeptAndAEmpsByStep(1);/*EmployeeDaoPlus dao2 = sqlSession.getMapper(EmployeeDaoPlus.class);Employee employee = dao2.getEmpById(department.getEmployee().get(0).getId());*/System.out.println(department);} catch (Exception e) {e.printStackTrace();} finally {sqlSession.close();}}
接口定义此处忽略
XML文件编写
<!-- collection分布查询 --><resultMap type="com.xuyong.entity.Department" id="DepartAndEmpByStep"><id column="id" property="id"/><result column="department_name" property="departmentName"/><collection property="employee" select="com.xuyong.dao.EmployeeDaoPlus.getEmpByDid" column="id"></collection></resultMap><!-- collection分布查询部门下的所有员工信息 --><select id="getDeptAndAEmpsByStep" resultMap="DepartAndEmpByStep">select id,department_name from departmentwhere id = #{id}</select>
查询结果
[com.xuyong.dao.DepartmentDao.getDeptAndAEmpsByStep]-==> Preparing: select id,department_name from department where id = ? [com.xuyong.dao.DepartmentDao.getDeptAndAEmpsByStep]-==> Parameters: 1(Integer)[com.xuyong.dao.DepartmentDao.getDeptAndAEmpsByStep]-<== Columns: id, department_name[com.xuyong.dao.DepartmentDao.getDeptAndAEmpsByStep]-<== Row: 1, 文案部[com.xuyong.dao.EmployeeDaoPlus.getEmpByDid]-====> Preparing: select * from employee where d_id = ? [com.xuyong.dao.EmployeeDaoPlus.getEmpByDid]-====> Parameters: 1(Integer)[com.xuyong.dao.EmployeeDaoPlus.getEmpByDid]-<==== Columns: id, last_name, gender, email, d_id[com.xuyong.dao.EmployeeDaoPlus.getEmpByDid]-<==== Row: 1, 徐永, 男, t1heluosh1@163.com, 1[com.xuyong.dao.EmployeeDaoPlus.getEmpByDid]-<==== Row: 4, 张三, 女, 123131313, 1[com.xuyong.dao.EmployeeDaoPlus.getEmpByDid]-<==== Total: 2[com.xuyong.dao.DepartmentDao.getDeptAndAEmpsByStep]-<== Total: 1Department [departmentName=文案部, employee=[Employee [dId=1, department=null, email=t1heluosh1@163.com, gender=男, id=1, lastName=徐永], Employee [dId=1, department=null, email=123131313, gender=女, id=4, lastName=张三]], id=1]
二、延迟加载
什么是延迟加载?
当我们在某项业务里需要同时获取A、B两份数据,但是B这份数据又不需要立即使用(或者存在压根就不会使用的情况),当程序需要加载B时,再去请求数据库来获取B数据,而不是一次性将数据全部取出来或者重新发送一份请求,这就是延迟加载。
MyBatis默认关闭延迟加载技术,需要我们在配置文件里手动配置,配置如下:
<!-- 设置 --><settings><!-- 驼峰命名映射 --><setting name="mapUnderscoreToCamelCase" value="true"/><setting name="jdbcTypeForNull" value="NULL"/><!-- 懒加载设置 --><setting name="lazyLoadingEnabled" value="true"/> <!-- 侵入懒加载,设置为false则按需加载,否则会全部加载 --><setting name="aggressiveLazyLoading" value="false"/><!-- 标准日志输出 --><!--<setting name="logImpl" value="STDOUT_LOGGING"/>--><!-- log4j日志输出 --><setting name="logImpl" value="LOG4J"/></settings>
注意:
1. lazyLoadingEnabled与aggressiveLazyLoading必须全部设置,且lazyLoadingEnabled为true,aggressiveLazyLoading为false才能让延迟加载真正生效
2. toString与重载方法过滤:
通常我们在测试时会在实体类加入toString,或者存在了一些重载方法,这些MyBatis会对其进行过滤,但是过滤会调 用cglib与asm指定包,因此要将两个包添加到buildpath。以下为两个包的maven依赖:
<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.1</version></dependency><dependency><groupId>asm</groupId><artifactId>asm</artifactId><version>3.3.1</version></dependency>
3.如果想单个开启或禁用延迟加载,可以使用fetchType属性来实现
<!-- collection分布查询 -->
<resultMap type="com.xuyong.entity.Department" id="DepartAndEmpByStep">
<id column="id" property="id"/>
<result column="department_name" property="departmentName"/>
<!-- 多个值传递可封装成map如:column="{key1=column1,...}"
fetchType="lazy" 表示使用懒加载 fetchType="eager"表示禁用懒加载
-->
<collection property="employee" select="com.xuyong.dao.EmployeeDaoPlus.getEmpByDid" column="{id=id}" fetchType="lazy"></collection>
</resultMap>
转载于:https://www.cnblogs.com/wang-Java-begining/p/9884927.html
MyBatis学习——分步查询与延迟加载相关推荐
- association 实现MyBatis分步查询与延迟加载
一.分步查询 1.1什么时候可以用到分步查询 有的时候需要我们对数据库进行关联查询,比如Employee 持有另一个Department对象的一个引用,我们希望在查询Employee 的时候把Depa ...
- mybatis分步查询与延迟加载
参考地址:https://blog.csdn.net/postersxu/article/details/79053916 本篇博客的主题是如何实现MyBatis的延迟加载(也叫懒加载),因为延迟加载 ...
- JavaEE——Mybatis(6)--association的分步查询与延迟加载 以及Collection和鉴别器discriminator...
使用association进行分步查询:(一般,部门什么的会有自己的Mappper,所以直接利用就好,不用再重新自己写) 1.先按照学生id查询学生信息 2.根据查询学生信息中的grade_id值去班 ...
- 【Java从0到架构师】MyBatis - 多表查询_延迟加载
多表查询_延迟加载 多表关系 一对一 association 标签 + JOIN 实现一对一 一对多 \ 多对一 collection 标签 + LEFT JOIN 实现一对多 多对多 多对多的本质: ...
- Mybatis的一对一查询以及延迟加载
一对一的关联查询: 使用业务扩展类 使用ResultMap 表如下 create table student(sid int(11) primary key not null, sname varch ...
- mybatis学习(22):查询排序
按照某列排序 目录结构 com.geyao.mybatis.mapper BlogMapper类 package com.geyao.mybatis.mapper;import java.util.L ...
- mybatis 学习的总结
什么是mybatis? 他是java基于持久层的框架(和数据库交互的一层),它支持定制化 SQL.存储过程以及高级映射(不像hibernate把发送sql作为暗箱操作,而他是可以完全看出来的可以看的到 ...
- [mybatis]映射文件_select_resultMap_关联查询_association分步查询延迟加载
association分步查询 场景一 查询Employee的同时查询员工对应的部门 Employee===Department 一个员工有与之对应的部门信息 Employee表: Departmen ...
- mybatis学习笔记(13)-延迟加载
2019独角兽企业重金招聘Python工程师标准>>> mybatis学习笔记(13)-延迟加载 标签: mybatis [TOC] resultMap可以实现高级映射(使用asso ...
最新文章
- 深证信息等三方拟联合开展大数据研究
- ModuleNotFoundError: No module named 'rospkg'
- 【赠书】重磅好书联邦学习实战来袭!你值得拥有一本
- Kafka 输入行太长 命令语法不正确
- mysql如何修改所有的definer
- z490 linux raid,华硕z490主板装win7系统及bios设置教程(支持10代usb驱动)
- 程序员职业自由6个阶段,你处于哪个?
- 对编码通俗易懂的介绍
- Android高级开发-布局渲染流程与优化
- 在你的网站中使用 AdSense广告
- java之mybatis之缓存
- $(function() {});和$(document).ready(function() {});区别
- 10万字208道Java经典面试题总结(附答案)
- linux -IOMMU
- oppo手机鸿蒙系统安装教程,oppo手机怎么刷机的步骤如下
- javascript有效的anagram挑战
- USYD悉尼大学DATA1002 详细作业解析Module6
- Java爬取frame的课程表_超级课程表一键提取课程功能app及课表静态网页内容
- Android 一定要培训吗,安卓开发需要学什么2
- 贪婪洞窟2服务器维护,12月24日贪婪洞窟2停服维护公告_贪婪洞窟2更新了什么_3DM手游...
热门文章
- 不止蔡徐坤,程序员也越努力越幸运?你是练习时长几年的程序员?
- antdesign卡片_10分钟精通Ant Design Form表单
- 关于android的sqlite问题,阳光沙滩-android studio的sqlite使用出现问题,是什么情况呢?...
- 国内星载光学卫星详解
- C语言 二分法查找与递归二分法查找
- Chino with Ciste
- depot_tools window 安装流程
- 【ROS入门学习01| ROS命令行工具的使用】
- 小恐龙游戏挑战:第11天-简单画好小恐龙并上色
- 使用phpExcelReader读取excel文件