引言
MyBatis中采用resultMap进行结果集映射,resultMap元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets数据提取代码中解放出来,并在一些情形下允许你进行一些 JDBC 不支持的操作。实际上,在为一些比如连接的复杂语句编写映射代码的时候,一份resultMap能够代替实现同等功能的数千行代码。ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了,可以说结果集映射是MyBatis的灵魂所在之处。
最简单的映射其实已经见过,这是一种隐式的映射,没有显式指定resultMap,句只是简单地将所有的列映射到 HashMap 的键上,这由 resultMap属性指定。虽然在大部分情况下都够用,但是 HashMap 不是一个很好的模型,程序更可能会使用 JavaBean 或POJO(Plain Old Java Objects,普通老式 Java 对象)作为模型。
<select id="selectUserById" resultType="map"> //返回HashMapselect id , name , pwd from user where id = #{id}</select>
resultMap之子标签result
java的po类属性命名和数据库字段的命名规范是不一样的,这样就会出现不能一一对应,先看一下如何解决属性名和字段名不一致的问题:
package com.wjh.po;
/**
* @author wjh
* @date 2021/7/12 20:39
* @Package com.wjh.po
*/
public class User2 {
private Integer id;
private String name;
private String password;
public User2() {
}
public User2(Integer id, String name, String password) {
this.id = id;
this.name = name;
this.password = password;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User2{" +
"id=" + id +
", name='" + name + '\'' +
", password='" + password + '\'' +
'}';
}
}
实体类的属性是id name password,而数据库字段却是id name pwd,解决方案是使用resultMap映射:
<?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.wjh.dao.User2Mapper">
<resultMap id="user2Map" type="com.wjh.po.User2">
<result column="pwd" property="password"/>
</resultMap>
<select id="getUserById" resultMap="user2Map">
select *
from user
where id = #{id}
</select>
</mapper>
其中select标签中的resultMap属性和resultMap中的id必须相对应,resultMap标签的type属性是实体对象的类,其子标签result表示数据库字段pwd映射成实体类属性的password的映射关系,可以有效解决数据库字段和实体类属性的命名冲突。
resultMap之子标签association
association主要用于多对一的处理
背景:多个学生对应一个老师,现在要查询所有学生的相关信息,Student类的属性有id、name、teacher,其中teacher属性是Teacher类的实例对象,Teacher类有id、name;而Student类对应的数据库字段是id、name、tid,Teacher对应的是id、name。
方案一(按查询嵌套处理):
<?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.wjh.dao.StudentMapper">
<select id="getStudents" resultMap="studentTeacher">
select *
from student
</select>
<resultMap id="studentTeacher" type="Student">
<association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
</resultMap>
<select id="getTeacher" resultType="Teacher">
select *
from teacher
where id = #{id}
</select>
</mapper>
当需要映射的属性是一个实例对象的时候,resultMap的子标签result已经力不从心了,这时候要使用新的子标签association来映射实例对象。property和column分别是属性和数据库字段,javaType是属性所属的类,select是嵌套查询对应的sql,而column的值则是sql语句中#{}的参数值。如果嵌套查询的sql需要多个参数,那么可以写成“column=”{key=value,key=value}””的形式。如:
方案二(按结果嵌套处理):
<?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.wjh.dao.StudentMapper">
<select id="getStudents" resultMap="studentTeacher">
select s.name sname, s.id sid, t.id tid, t.name tname
from student s,
teacher t
where s.tid = t.id
</select>
<resultMap id="studentTeacher" type="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
</association>
</resultMap>
</mapper>
可以看到先使用多表查询查询出所有结果,然后再一一映射,先把数据库字段映射成普通属性,在把其余相应的字段映射成teacher属性。
resultMap之子标签collection
collection主要用于处理一对多的问题
背景:一个老师对应多个学生,现在要根据老师id来查询一个Teacher对象,Teacher类的属性包括id、name、students,其中students是List
方案一(按查询嵌套处理):
<?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.wjh.dao.TeacherMapper">
<select id="getTeacherById" resultMap="teacherMap">
select *
from teacher
where id = #{tid}
</select>
<resultMap id="teacherMap" type="Teacher">
<result property="id" column="id"/>
<result property="name" column="name"/>
<collection property="students" javaType="List" ofType="Student" select="getStudents" column="id"/>
</resultMap>
<select id="getStudents" resultType="Student">
select * from student where tid=#{tid}
</select>
</mapper>
collection标签的javaType指的是集合的类型(如List、Set、Map),而ofType则指定的集合的具体泛型,column指需要传递给嵌套的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="com.wjh.dao.TeacherMapper">
<select id="getTeacherById" resultMap="teacherMap">
select t.id tid, t.name tname, s.id sid, s.name sname, s.id sid
from teacher t,
student s
where t.id = s.tid
and t.id = #{tid}
</select>
<resultMap id="teacherMap" type="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<collection property="students" javaType="List" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="tname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
</mapper>
collection标签的javaType指的是集合的类型(如List、Set、Map),而ofType则指定的集合的具体泛型。
小结
resultMap常用的映射标签有:id、result、association、collection,id一般用于主键映射,但是result同样可以用于主键映射,因此推荐统一使用result,而且result还可以映射po类对象的普通属性,而id做不到;assocation是用来映射对象属性的,一般用于一对一和多对一的情况;collection是用来映射集合属性的,一般用于一对多,且该标签的JavaType属性是用来指定po中属性的类型,而odType则用来指定集合的具体泛型。
