多对一:
多种方式,常见的包括三种:
-
第一种方式:一条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;}@Overridepublic 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 mapperPUBLIC "-//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">SELECTs.sid, s.sname, c.cid, c.cnameFROMt_student_plus sLEFT JOINt_clazz c ON s.cid = c.cidWHEREs.sid = #{sid}</select></mapper>
@Testpublic 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">SELECTs.sid, s.sname, c.cid, c.cnameFROMt_student_plus sLEFT JOINt_clazz c ON s.cid = c.cidWHEREs.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 mapperPUBLIC "-//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;}@Overridepublic 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"