Mybatis分解式查询使用方法
作者:会洗碗的CV工程师 发布时间:2023-08-16 04:15:06
一、Mybatis一对多分解式查询
分解式查询就是将一条Sql语句拆分成多条
在MyBatis多表查询中,使用连接查询时一个Sql语句就可以查询出所有的数据。如:
# 查询班级时关联查询出学生
select *
from classes
left join student
on student.classId = classes.cid
也可以使用分解式查询,即将一个连接Sql语句分解为多条Sql语句,如:
# 查询班级时关联查询出学生
select * from classes;
select * from student where classId = 1;
select * from student where classId = 2;
这种写法也叫N+1查询。
连接查询:
优点:降低查询次数,从而提高查询效率。
缺点:如果查询返回的结果集较多会消耗内存空间。
N+1查询:
优点:结果集分步获取,节省内存空间。
缺点:由于需要执行多次查询,相比连接查询效率低。
我们以查询班级时关联查询出学生为例,使用N+1查询:
1. 新增持久层接口方法
新增ClassesMapper2.java接口
package com.example.mapper;
import com.example.pojo.Classes;
import java.util.List;
public interface ClassesMapper2 {
List<Classes> findAll();
}
新增StudentMapper.java接口
package com.example.mapper;
import com.example.pojo.Student;
import java.util.List;
public interface StudentMapper2 {
List<Student> findByClassId(int classId);
}
2. 新增映射文件对应的标签
新增ClassesMapper.xml映射文件
<?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.example.mapper.ClassesMapper2">
<!-- 自定义映射关系 -->
<resultMap id="myClassesMapper" type="com.example.pojo.Classes">
<id property="cid" column="cid"/>
<result property="className" column="className"/>
<!-- select: 从表查询调用的方法 column:调用方法时传入的参数字段 -->
<collection property="studentList" column="cid"
ofType="com.example.pojo.Student"
select="com.example.mapper.StudentMapper2.findByClassId"/>
</resultMap>
<select id="findAll" resultMap="myClassesMapper">
select * from classes
</select>
</mapper>
新增StudentMapper.xml映射文件
<?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.example.mapper.StudentMapper2">
<select id="findByClassId"
parameterType="int"
resultType="com.example.pojo.Student">
select * from student where classId = ${classId}
</select>
</mapper>
3. 新增测试方法
// 分解式查询一对多
@Test
public void testFindAllClasses2(){
ClassesMapper2 classesMapper2 = session.getMapper(ClassesMapper2.class);
List<Classes> all = classesMapper2.findAll();
all.forEach(System.out::println);
}
4. 运行效果
在这里我们可以看到确实是分开了了两条查询语句
二、Mybatis一对一分解式查询
查询学生时关联查询出班级也可以使用分解式查询,首先将查询语句分开:
select * from student;
select * from classes where cid = ?
1. 新增持久层接口方法
新增StudentMapper3.java接口
package com.example.mapper;
import com.example.pojo.Student;
import java.util.List;
public interface StudentMapper3 {
// 查询所有学生
List<Student> findAll();
}
新增ClassesMapper3.java接口
package com.example.mapper;
import com.example.pojo.Classes;
import java.util.List;
public interface ClassesMapper3 {
// 根据ID查询班级
Classes findById(int cid);
}
2. 新增映射文件对应的标签
新增ClassesMapper.xml映射文件
<?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.example.mapper.ClassesMapper3">
<select id="findByCid"
resultType="com.example.pojo.Classes"
parameterType="int">
select * from classes where cid = ${cid}
</select>
</mapper>
新增StudentMapper.xml映射文件
<?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.example.mapper.StudentMapper3">
<!-- 自定义映射关系 -->
<resultMap id="MyClassesMapper" type="com.example.pojo.Student">
<id property="sid" column="sid"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
<result property="sex" column="sex"/>
<!-- select: 从表查询调用的方法 column:调用方法时传入的参数字段 -->
<association property="classes" column="classId"
javaType="com.example.pojo.Classes"
select="com.example.mapper.ClassesMapper3.findByCid"/>
</resultMap>
<select id="findAll" resultMap="MyClassesMapper">
select * from student
</select>
</mapper>
3. 新增测试方法
// 分解式查询一对一
@Test
public void testFindAllStudent2(){
StudentMapper3 studentMapper3 = session.getMapper(StudentMapper3.class);
List<Student> all = studentMapper3.findAll();
all.forEach(System.out::println);
}
4. 运行效果
OK,确实是查询出来了。
三、Mybatis延迟加载
分解式查询又分为两种加载方式:
立即加载:在查询主表时就执行所有的Sql语句。
延迟加载:又叫懒加载,首先执行主表的查询语句,使用从表数据时才触发从表的查询语句。
延迟加载在获取关联数据时速度较慢,但可以节约资源,即用即取。
1. 开启延迟加载
设置所有的N+1查询都为延迟加载,在Mybatis配置文件中添加以下设置:
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="lazyLoadTriggerMethods" value=""/>
</settings>
设置某个方法为延迟加载:
在 <association> 、 <collection> 中添加fetchType属性设置加载方式。
lazy:延迟加载;eager:立即加载。
2. 测试延迟加载
由于打印对象时会调用对象的 toString 方法, toString 方法默认会触发延迟加载的查询,所以我们无法测试出延迟加载的效果。
我们在配置文件设置lazyLoadTriggerMethods属性,该属性指定对象的什么方法触发延迟加载,设置为空字符串即可。
测试方法:
@Test
public void testFindAllClasses2(){
ClassesMapper2 classesMapper2 = session.getMapper(ClassesMapper2.class);
List<Classes> all = classesMapper2.findAll();
all.forEach(System.out::println);
System.out.println("---------------------");
System.out.println(all.get(0).getStudentList());
}
运行结果:
OK,这个很明显了,就是第一次查询的时候没有将学生列表查询出来,等到后续需要查询的时候载查询。
一般情况下,一对多查询使用延迟加载,一对一查询使用立即加载。
来源:https://blog.csdn.net/qq_53317005/article/details/129634685


猜你喜欢
- 关于在spring 容器初始化 bean 和销毁前所做的操作定义方式有三种:第一种:通过注解@PostConstruct 和 @
- 这个例子只是简单实现了如何使用 Socket 类实现面向连接的通信。注意:此例子的目的只是为了说明用套接字写程序的大概思路,而不是实际项目中
- @RequestBody部分属性丢失问题描述JavaBean实现public class VerifyNewFriendApplyReq i
- Fragment 的简单用法Fragment 是一种可以嵌入在 Activity 当中的 UI 片段,它能让程序更加合理和充分地利用大屏幕的
- 配置绑定所谓配置绑定”就是把配置文件中的值与 JavaBean 中对应的属性进行绑定。通常,我们会把一些配置信息(例如,
- 开发Android APP微信支付功能,需要完成三个步骤:第一步生成预支付订单、第二步生成微信支付参数、第三步调起微信APP支付。除了需要审
- 以前一直看见 i18N ,现在才知道原来 i18N 就是 Internationalization,因为以 i 开头,以 N 结尾,共18个
- 先来个效果图觉得不好看可以自己调整1.绘制数据点线状图一般由数据点和连线组成在绘制连线之前,我们先标出数据点这里我选择用Image图片来绘制
- Stripe支付首页需要引用Stripe.net框架,我引用的是22.8.0版本,注意.NETFramework的版本为4.5,同时需要引用
- 一、位运算的分类与展现效果java位运算可以分为左移和右移,其中右移还有无符号右移。 java只对整型位移,可以分为int体系和long体系
- jdk * 和cglib * 实现及区别代理模式是一种设计模式,提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不
- //路径, 添加开机启动/删除开机启动 public s
- 一、Future 接口当 call()方法完成时,结果必须存储在主线程已知的对象中,以便主线程可以知道该线程返回的结果。为此,可以使用 Fu
- 注意:导包的时候API 11之前: android.text.ClipboardManagerAPI 11之后: android.conte
- 一般情况下在Word中输入的文字都是横向的,今天给大家分享两种方法来设置/更改一个section内的所有文本的方向及部分文本的方向,有兴趣的
- 本文实例为大家分享了Java中Stream流去除List重复元素的具体代码,供大家参考,具体内容如下业务场景在开发中我们常常需要过滤List
- C# 4.0提供了一个dynamic 关键字,那么什么是dynamic,究竟dynamic是如何工作的呢?从最简单的示例开始:static
- 本文以实例形式讲述了C#通过反射创建自定义泛型的实现方法,分享给大家供大家参考。具体如下:比如有这样一个泛型:Demo.GenericsSi
- java parseInt()
- 前言C#方法中参数类型有4种参数类型,有时候很难记住它们的不同特征,下图对它们做一个总结大家可能在编码中或多或少的使用过out的ref,但是