Table of contents
1. Mybatis one-to-many decomposition query
1. Add new persistence layer interface method
2. Add the label corresponding to the mapping file
Two, Mybatis one-to-one decomposition query
1. Add new persistence layer interface method
2. Add the label corresponding to the mapping file
1. Mybatis one-to-many decomposition query
Decomposed query is to split a Sql statement into multiple
In MyBatis multi-table query, all data can be queried with one Sql statement when using connection query. like:
# When querying the class, associate the query with the students
select *
from classes
left join student
on student.classId = classes.cid
You can also use decomposed query, that is, decompose a connection Sql statement into multiple Sql statements, such as:
# When querying the class, associate the query with the students
select * from classes;
select * from student where classId = 1;
select * from student where classId = 2;
This way of writing is also called N+1 query .
Connection query :
Advantages: reduce the number of queries, thereby improving query efficiency.
Disadvantage: If the query returns a large number of result sets, it will consume memory space.
N+1 query :
Advantages: The result set is obtained step by step, saving memory space.
Disadvantages: Due to the need to execute multiple queries, it is less efficient than join queries.
Let's take the related query of students when querying classes as an example, and use N+1 query:
1. Add new persistence layer interface method
Added ClassesMapper2.java interface
package com.example.mapper;
import com.example.pojo.Classes;
import java.util.List;
public interface ClassesMapper2 {
List<Classes> findAll();
}
Add StudentMapper.java interface
package com.example.mapper;
import com.example.pojo.Student;
import java.util.List;
public interface StudentMapper2 {
List<Student> findByClassId(int classId);
}
2. Add the label corresponding to the mapping file
Added ClassesMapper.xml mapping file
<?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>
Add StudentMapper.xml mapping file
<?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. New test method
// 分解式查询一对多
@Test
public void testFindAllClasses2(){
ClassesMapper2 classesMapper2 = session.getMapper(ClassesMapper2.class);
List<Classes> all = classesMapper2.findAll();
all.forEach(System.out::println);
}
4. Operation effect
Here we can see that two query statements are indeed separated
Two, Mybatis one-to-one decomposition query
When querying students, you can also use the decomposed query to associate the query to find out the class. First, separate the query statement:
select * from student;
select * from classes where cid = ?
1. Add new persistence layer interface method
Add StudentMapper3.java interface
package com.example.mapper;
import com.example.pojo.Student;
import java.util.List;
public interface StudentMapper3 {
// 查询所有学生
List<Student> findAll();
}
Added ClassesMapper3.java interface
package com.example.mapper;
import com.example.pojo.Classes;
import java.util.List;
public interface ClassesMapper3 {
// 根据ID查询班级
Classes findById(int cid);
}
2. Add the label corresponding to the mapping file
Added ClassesMapper.xml mapping file
<?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>
Add StudentMapper.xml mapping file
<?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. New test method
// 分解式查询一对一
@Test
public void testFindAllStudent2(){
StudentMapper3 studentMapper3 = session.getMapper(StudentMapper3.class);
List<Student> all = studentMapper3.findAll();
all.forEach(System.out::println);
}
4. Operation effect
OK, indeed the query came out.
3. Mybatis lazy loading
Decomposed queries are further divided into two loading methods:
Immediate loading: Execute all Sql statements when querying the main table.
Lazy loading: also known as lazy loading, the query statement of the main table is executed first, and the query statement of the secondary table is triggered only when the data of the secondary table is used.
Lazy loading is slower when fetching associated data, but it saves resources and fetches it as it is used.
1. Enable lazy loading
Set all N+1 queries as lazy loading, add the following settings in the Mybatis configuration file:
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="lazyLoadTriggerMethods" value=""/>
</settings>
Set a method as lazy loading:
Add the fetchType attribute in <association> and <collection> to set the loading method.
lazy: lazy loading; eager: immediate loading.
2. Test lazy loading
Since the toString method of the object will be called when printing the object, the toString method will trigger the query of lazy loading by default, so we cannot test the effect of lazy loading.
We set the lazyLoadTriggerMethods attribute in the configuration file. This attribute specifies what method of the object triggers lazy loading, and it can be set to an empty string.
Test Methods:
@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());
}
operation result:
OK, this is obvious, that is, the student list was not queried in the first query, and the query will be uploaded when the subsequent query is needed.
In general, lazy loading is used for one-to-many queries, and immediate loading is used for one-to-many queries.