MyBatis高级映射及延迟加载的实现
作者:代码代码快快显灵
多对一:
多种方式,常见的包括三种:
第一种方式:一条SQL语句,级联属性映射。
第二种方式:一条SQL语句,association。
第三种方式:两条SQL语句,分步查询。(这种方式常用:优点一是可复用。优点二是支持懒加载。)
怎么区分主表和副表?
原则:谁在前面谁是主表
例如:多对一,多在前面,那么多的那个表就是主表
级联属性映射:
Student类:
package pojo; /** * 学生信息 * 没有cid这个属性,后期会有特殊的方式来处理这个关系字段 */ public class Student { private Integer sid; private String sname; private Clazz clazz; public Clazz getClazz() { return clazz; } public void setClazz(Clazz clazz) { this.clazz = clazz; } @Override public String toString() { return "Student{" + "sid=" + sid + ", sname='" + sname + '\'' + ", clazz=" + clazz + '}'; } public Student() { } public Student(Integer sid, String sname) { this.sid = sid; this.sname = sname; } public Integer getSid() { return sid; } public void setSid(Integer sid) { this.sid = sid; } public String getSname() { return sname; } public void setSname(String sname) { this.sname = sname; } }
对应的sql映射文件:
<?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="mapper.StudentMapper"> <!-- 级联属性映射 --> <resultMap id="studentResultMap" type="Student"> <id property="sid" column="sid"/> <result property="sname" column="sname"/> <result property="clazz.cid" column="cid"/> <result property="clazz.cname" column="cname"/> </resultMap> <select id="selectById" resultMap="studentResultMap"> SELECT s.sid, s.sname, c.cid, c.cname FROM t_student_plus s LEFT JOIN t_clazz c ON s.cid = c.cid WHERE s.sid = #{sid} </select> </mapper>
@Test public void testSelectBySid(){ StudentMapper mapper = SqlSessionUtil.openSession().getMapper(StudentMapper.class); Student student = mapper.selectBySid(1); System.out.println(student); }
sql语句:
2024-10-14 13:29:58.511 [main] DEBUG mapper.StudentMapper.selectById - ==> Preparing:
SELECT s.sid, s.sname, c.cid, c.cname FROM t_student_plus s
LEFT JOIN t_clazz c ON s.cid = c.cid WHERE s.sid = ?
association
对应的sql映射文件:
<resultMap id="studentResultMapAssociation" type="Student"> <id property="sid" column="sid"/> <result property="sname" column="sname"/> <!-- 嵌套映射,将 clazz 对象中的 cid 和 cname 映射 --> <association property="clazz" javaType="Clazz"> <id property="cid" column="cid"/> <result property="cname" column="cname"/> </association> </resultMap> <select id="selectByIdAssociation" resultMap="studentResultMap"> SELECT s.sid, s.sname, c.cid, c.cname FROM t_student_plus s LEFT JOIN t_clazz c ON s.cid = c.cid WHERE s.sid = #{sid} </select>
association翻译为:关联。 学生对象关联一个班级对象。
关键点说明
<resultMap>
元素:resultMap
用于映射结果集到 Java 对象。通过定义StudentResultMap
来描述如何将查询结果映射到Student
对象。<association>
元素:<association>
用于处理多对一的关系映射。它会把clazz
的数据映射到Student
对象的clazz
属性上。property
:对应Student
类中的clazz
属性。javaType
:指定Clazz
类的全限定名。- 通过
property
和column
进行字段的映射。
SQL 查询:
selectStudentWithClazz
查询使用了LEFT JOIN
来同时获取student
和clazz
的信息,并通过resultMap
映射到Student
对象中。
分步查询
<resultMap id="studentResultMapByStep" type="Student"> <id property="sid" column="sid"/> <id property="sname" column="sname"/> <association property="clazz" select="mapper.ClazzMapper.selectByCid" column="cid"/> </resultMap> <!--两条sql语句,完成多对一的分布查询--> <!-- 这是第一步,根据id值查询学生的所有信息,这些信息当中含有班级id(cid--> <select id="selectByIdStep1" resultMap="studentResultMapByStep" > select sid,sname,cid from t_student_plus where sid = #{sid} </select>
解释:
- <resultMap id="studentResultMap" type="Student">:定义了一个结果映射规则,结果将映射到 Student 对象中。
- <id property="sid" column="sid"/>:将数据库中的 sid 列映射到 Student 类的 sid 属性,通常用于映射主键。
- <result property="sname" column="sname"/>:将数据库中的 sname 列映射到 Student 类的 sname 属性。
- <association>:用于描述一个对象属性与其他查询之间的关联。
- property="clazz":Student 类中对应的属性名是 clazz,它表示学生所属的班级。
- select="com.powernode.mybatis.mapper.ClazzMapper.selectByCid":指定调用的查询方法,用于获取 Clazz 信息。
- column="cid":指定当前查询结果中的 cid 列的值,将其作为参数传递给 selectByCid 方法。
在ClazzMapper接口中添加方法
public interface ClazzMapper { /** * 分布查询第二步 * 根据cid获取Clazz信息 * @param cid * @return */ Clazz selectByCid(Integer cid); }
ClazzMapper的sql映射文件:
<?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="mapper.ClazzMapper"> <select id="selectByCid" resultType="Clazz"> select cid,cname from t_clazz where cid = #{cid} </select> </mapper>
执行结果,可以很明显看到先后有两条sql语句执行:
延迟加载
一对多延迟加载机制和多对一是一样的。同样是通过两种方式:
第一种:fetchType="lazy"
<resultMap id="studentResultMapByStep" type="Student"> <id property="sid" column="sid"/> <id property="sname" column="sname"/> <association property="clazz" select="mapper.ClazzMapper.selectByCid" column="cid" fetchType="lazy"/> <!--添加延迟--> </resultMap> <!--两条sql语句,完成多对一的分布查询--> <!-- 这是第一步,根据id值查询学生的所有信息,这些信息当中含有班级id(cid--> <select id="selectByIdStep1" resultMap="studentResultMapByStep" > select sid,sname,cid from t_student_plus where sid = #{sid} </select>
第二种:修改全局的配置setting,lazyLoadingEnabled=true,如果开启全局延迟加载,想让某个sql不使用延迟加载:fetchType="eager"
一对多
一对多的实现,通常是在一的一方中有List集合属性。
在Clazz类中添加List<Student> stus; 属性。
package pojo; import java.util.List; /** * 班级信息 */ public class Clazz { public Clazz() { } private Integer cid; private String cname; private List<Student> stus; public List<Student> getStus() { return stus; } @Override public String toString() { return "Clazz{" + "cid=" + cid + ", cname='" + cname + '\'' + ", stus=" + stus + '}'; } public void setStus(List<Student> stus) { this.stus = stus; } public Integer getCid() { return cid; } public void setCid(Integer cid) { this.cid = cid; } public String getCname() { return cname; } public void setCname(String cname) { this.cname = cname; } public Clazz(Integer cid, String cname) { this.cid = cid; this.cname = cname; } }
一对多的实现通常包括两种实现方式:
- 第一种方式:collection
- 第二种方式:分步查询
collection:
public interface ClazzMapper { /** * 根据cid获取Clazz信息 * @param cid * @return */ Clazz selectByCid(Integer cid); /** * 根据班级编号查询班级信息。同时班级中所有的学生信息也要查询。 * @param cid * @return */ Clazz selectClazzAndStusByCid(Integer cid); }
<resultMap id="clazzResultMap" type="Clazz"> <id property="cid" column="cid"/> <result property="cname" column="cname"/> <collection property="stus" ofType="Student"> <id property="sid" column="sid"/> <result property="sname" column="sname"/> </collection> </resultMap> <select id="selectClazzAndStusByCid" resultMap="clazzResultMap"> select * from t_clazz c join t_student s on c.cid = s.cid where c.cid = #{cid} </select>
注意是ofType,表示“集合中的类型”!!!
分步查询:
<resultMap id="clazzResultMap" type="Clazz"> <id property="cid" column="cid"/> <result property="cname" column="cname"/> <!--主要看这里--> <collection property="stus" select="com.powernode.mybatis.mapper.StudentMapper.selectByCid" column="cid"/> </resultMap> <!--sql语句也变化了--> <select id="selectClazzAndStusByCid" resultMap="clazzResultMap"> select * from t_clazz c where c.cid = #{cid} </select>
/** * 根据班级编号获取所有的学生。 * @param cid * @return */ List<Student> selectByCid(Integer cid);
<select id="selectByCid" resultType="Student"> select * from t_student where cid = #{cid} </select>
延迟加载
一对多延迟加载机制和多对一是一样的。同样是通过两种方式:
- 第一种:fetchType="lazy"
- 第二种:修改全局的配置setting,lazyLoadingEnabled=true,如果开启全局延迟加载,想让某个sql不使用延迟加载:fetchType="eager"
到此这篇关于MyBatis高级映射及延迟加载的实现的文章就介绍到这了,更多相关MyBatis高级映射及延迟加载内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!