在常规的CRUD中,POJO大多数属性都是基本类型,但是稍微复杂一点的项目,便会出现引用类型,那么普通的SQL就不容易处理了,幸好Mybatis提供了一个非常强大的工具——resultMap
MyBatis映射文件中除了 <insert> 、 <delete> 、 <update> 、 <select> 外,还有一些标签可以使用:
本小节主要来记录 <resultMap>
标签的作用:自定义映射关系。
MyBatis可以将数据库结果集封装到对象中,是因为结果集的列名和对象属性名相同:
当POJO属性名和数据库列名不一致时,MyBatis无法自动完成映射关系。如:
此时有两种解决方案:
①Sql语句的查询字段起与POJO属性相同的别名。
<select id="findAll" resultType="com.nucty.pojo.Teacher">
select tid as id,tname as teacherName from teacher;
</select>
②自定义映射关系
<!-- 在select标签中,使用resultMap属性代替resultType属性,使用自定义映射关系。 -->
<select id="findAll" resultMap="teacherMapper">
select * from teacher
</select>
<resultMap id="teacherMapper" type="com.nucty.pojo.Teacher">
<!-- id定义主键列 property:POJO属性名 column:数据库列名 -->
<id property="id" column="tid"></id>
<!-- result定义普通列 property:POJO属性名 column:数据库列名 -->
<result property="teacherName" column="tname"></result>
</resultMap>
查询班级时,将关联的一个老师对象查询出来,就是一对一关联查询。【虽然班级和老师是多对多的关系,但是数据库中一个班级对应的是一个老师去模拟一对一的关联查询】
创建持久层接口
@Mapper
public interface IClassDao {
public Classs getClass(Integer id);
}
创建映射文件
<select id="getClass" parameterType="Integer" resultMap="ClassResultMap">
select *
from class c,
teacher t
where c.teacher_id = t.t_id
and c.c_id = #{id}
</select>
<resultMap id="ClassResultMap" type="nuc.ty._20231202myatis.pojo.Classs">
<!-- id定义主键列 property:POJO属性名 column:数据库列名 -->
<id property="id" column="c_id"></id>
<!-- result定义普通列 property:POJO属性名 column:数据库列名 -->
<result property="name" column="c_name"></result>
<!-- 一对一对象列 property:属性名 column:关联列名 javaType:对象类型-->
<association property="teacher" column="teacher_id" javaType="nuc.ty._20231202myatis.pojo.Teacher">
<!-- 关联对象主键列 -->
<id property="id" column="t_id"/>
<!-- 关联对象普通列 -->
<result property="name" column="t_name"/>
</association>
</resultMap>
现给出另外一种实现方式,观察区别
<select id="getClass2" parameterType="integer" resultMap="ClassResultMap2">
select *
from class
where c_id = #{id}
</select>
<resultMap id="ClassResultMap2" type="nuc.ty._20231202myatis.pojo.Classs">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<!-- 一对一对象列
property:属性名
column:关联列名
javaType:对象类型
select:指定映入嵌套查询的子 SQL 语句,即使用另一个查询封装的结果。
-->
<association property="teacher" column="teacher_id" javaType="nuc.ty._20231202myatis.pojo.Teacher"
select="getTeacher">
</association>
</resultMap>
<select id="getTeacher" parameterType="Integer" resultType="nuc.ty._20231202myatis.pojo.Teacher">
select t_id id, t_name name
from teacher
where t_id = #{id}
</select>
其区别在于嵌套查询和嵌套结果查询【着重关注一下sql语句的区别】
嵌套查询 是指通过执行另外一条 SQL 映射语句来返回预期的复杂类型;
嵌套结果 是使用嵌套结果映射来处理重复的联合结果的子集。
嵌套查询 | 嵌套结果 |
---|---|
嵌套查询是在查询 SQL 后再进行一个(子)查询 | 嵌套结果是一个多表查询的 SQL 语句 |
会执行多条 SQL 语句 | 只有一条复杂的 SQL 语句(多表连接) |
SQL语句编写较为简单 | SQL语句编写较为复杂 |
参考链接:Mybatis 的嵌套查询与嵌套结果的区别 - 东郊 - 博客园 (cnblogs.com)
查询一个部门下的员工信息【模拟一对多关联查询】
创建持久层接口
@Mapper
public interface IDeptDao {
public Dept findByDeptno(Integer deptno);
}
创建映射文件
<mapper namespace="nuc.ty._20231202myatis.dao.IDeptDao">
<!--根据部门编号查询员工 -->
<select id="findByDeptno" parameterType="Integer" resultMap="deptMap">
select *
from dept
where deptno = #{deptno}
</select>
<resultMap type="nuc.ty._20231202myatis.pojo.Dept" id="deptMap">
<id property="deptno" column="deptno"/>
<result property="dname" column="dname"/>
<result property="location" column="loc"/>
<!-- collection:一对多关联映射
根据部门deptno先读取部门信息,然后再读取这个部门所有的用户信息。
property表示集合类型属性名称,也就是Dept实体类中定义的员工List名字
ofType表示集合中的对象的类型-->
<collection property="emps" javaType="ArrayList"
ofType="nuc.ty._20231202myatis.pojo.Emp"
column="deptno"
select="nuc.ty._20231202myatis.dao.IEmpDao.findByDeptno">
</collection>
</resultMap>
</mapper>
<mapper namespace="nuc.ty._20231202myatis.dao.IEmpDao">
<!--根据deptno查询员工-->
<select id="findByDeptno" parameterType="Integer"
resultType="nuc.ty._20231202myatis.pojo.Emp">
select * from emp
where deptno=#{deptno}
</select>
</mapper>
<collection>子元素属性大部分与<association>元素相同,但其还包含一个特殊属性-ofType 属性,ofType 属性与< association>中的javaType属性对应,用于指定实体对象中集合类属性所包含的元素类型。
举例说明:
在一对一关联查询中,javaType雀雀实实指的是对象的类型。
而在一对多关联查询中,ofType指的是实体对象中集合类属性所包含的元素类型即Emp,而javaType指的是集合类型,一般指ArrayList。