在真实的业务场景中,使用resultType进行输出映射,只有查询出来的列名和pojo(实体bean)中的属性名一致,该列才可以映射成功。简单来说也就是你的数据库字段和JavaBean里的字段名称必须一致才能映射成功。
当JavaBean中的字段名和数据库字段名称有不同的时候,或者是多表查询的时候,一般会使用resultMap。
什么是resultMap
resultMap是Mybatis最强大的元素,它可以将查询到的复杂数据(比如查询到几个表中数据)映射到一个结果集当中。
resultMap的作用
resultMap的作用是定义映射规则、级联的更新、定制类型转化器等。resultMap定义的主要是一个结果集的映射关系,也就是sql到java bean的映射关系定义,它也支持级联等特性。
resultMap的元素构成
resultMap元素的子元素:
<resultMap> <constructor> <idArg/> <arg> </constructor> <id/> <result/> <association/> <collection/> <discriminator> <case/> </discriminator> </resultMap>
resultMap的语法
<!--column不做限制,可以为任意表的字段,而property须为type 定义的pojo属性--> <resultMap id="唯一的标识" type="映射的pojo对象"> <id column="表的主键字段,或者可以为查询语句中的别名字段" jdbcType="字段类型" property="映射pojo对象的主键属性" /> <result column="表的一个字段(可以为任意表的一个字段)" jdbcType="字段类型" property="映射到pojo对象的一个属性(须为type定义的pojo对象中的一个属性)"/> <association property="pojo的一个对象属性" javaType="pojo关联的pojo对象"> <id column="关联pojo对象对应表的主键字段" jdbcType="字段类型" property="关联pojo对象的主席属性"/> <result column="任意表的字段" jdbcType="字段类型" property="关联pojo对象的属性"/> </association> <!-- 集合中的property须为oftype定义的pojo对象的属性--> <collection property="pojo的集合属性" ofType="集合中的pojo对象"> <id column="集合中pojo对象对应的表的主键字段" jdbcType="字段类型" property="集合中pojo对象的主键属性" /> <result column="可以为任意表的字段" jdbcType="字段类型" property="集合中的pojo对象的属性" /> </collection> </resultMap>
如果collection标签是使用嵌套查询,格式如下:
<collection column="传递给嵌套查询语句的字段参数" property="pojo对象中集合属性" ofType="集合属性中的pojo对象" select="嵌套的查询语句" > </collection>
注意:<collection>标签中的column:要传递给select查询语句的参数,如果传递多个参数,格式为column= ” {参数名1=表字段1,参数名2=表字段2} ;
resultMap的应用
比如,数据库中字段名称为id,name,age,sex 而对应java代码中pojo的属性名分别为id,username,age,sex。可以看出姓名列不一致,这个时候就需要使用resultMap来将字段名和属性名对应起来,进行手动配置封装,将结果映射到pojo中。
<!-- resultMap最终还是要将结果映射到pojo上,type就是指定映射到哪一个pojo --> <!-- id:设置ResultMap的id --> <resultMap type="user" id="userMap"> <!-- 定义主键 ,非常重要。如果是多个字段,则定义多个id --> <!-- property:pojo里的属性名 column:数据库中的列名 --> <id property="id" column="id" /> <!-- 定义普通属性 property:pojo里的属性名 column:数据库中的列名--> <result property="username" column="name" /> <result property="age" column="age" /> <result property="sex" column="sex" /> </resultMap> <!-- resultMap:填入配置的resultMap标签的id值 --> <select id="findUser" resultMap="userMap"> select id,name,age,sex from user </select>
级联
Mybatis的级联操作主要是针对一对多、多对一和多对多的情况而设定的。级联是在resultMap标签中配置的。级联并不是必须的,好处就是获取关联数据便捷,但如果级联过多会增加系统的复杂度,同时降低系统的性能。所以记录超过3层时,就不要考虑使用级联了,因为这样会造成多个对象的关联,导致系统的耦合、负载和难以维护。
一对一
业务场景:订单用户,一条订单信息只能对应一个用户,此为一对一。做法如下:
1. 改造订单的pojo类:
(添加User属性--User属性是一个引用类型,用于存储关联查询的用户信息,因为关联关系是一对一,所以只需要添加单个属性即可)
//订单类 pulic class Order{ //原order属性 private int id; private Integer userId; private String number; private Date createtime; private String note; //新加user属性 private User user; //下面省略get和set方法 } //用户信息类 pulic void User{ private int id; private String username; private String address; //下面省略get和set方法 }
2. 修改mapper.xml配置文件
(使用resultMap和association标签来实现一对一)
<resultMap type="order" id="orderUserResultMap"> <!-- 第一步:配置Order类的对应关系 --> <!-- property:pojo里的属性名 column:数据库中的列名 --> <id property="id" column="id" /> <result property="userId" column="user_id" /> <result property="number" column="number" /> <result property="createtime" column="createtime" /> <result property="note" column="note" /> <!-- 第二步:配置User类的对应关系 --> <!-- association :配置一对一属性 property:order里面的User属性名 javaType:属性类型--> <association property="user" javaType="user"> <!-- id:声明主键,表示user_id是关联查询对象的唯一标识 --> <!-- 简单说就是:id标签:(property:user表的主键名称 column:对应Order表的外键名称) result标签下的都是user表的内容--> <id property="id" column="user_id" /> <result property="username" column="username" /> <result property="address" column="address" /> </association> </resultMap> <!-- 一对一关联,查询订单,订单内部包含用户属性 --> <select id="queryOrderUserResultMap" resultMap="orderUserResultMap"> SELECT a.id,a.user_id,a.number,a.createtime,a.note,b.username,b.address from order a left join user b on a.user_id = b.id </select>
3. 测试代码:
@Test public void testQueryOrderUserResultMap() { // mybatis和spring整合,整合之后,交给spring管理 SqlSession sqlSession = this.sqlSessionFactory.openSession(); // 创建Mapper接口的动态代理对象,整合之后,交给spring管理 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); // 使用userMapper执行根据条件查询用户,结果封装到Order类中 List<Order> list = userMapper.queryOrderUserResultMap(); for (Order o : list) { System.out.println(o); } // mybatis和spring整合,整合之后,交给spring管理 sqlSession.close(); }
一对多
业务场景:订单用户,一个用户对应多条订单信息,此为一对多。做法如下:
1. 改造用户的pojo类:
(添加订单集合属性)
//订单类 pulic class Order{ private int id; private Integer userId; private String number; private Date createtime; private String note; //下面省略get和set方法 } //用户信息类 pulic void User{ //原用户属性 private int id; private String username; private String address; //新加订单集合属性 private List<Order> orders; //下面省略get和set方法 }
2. 修改mapper.xml配置文件
(使用resultMap和collection标签来实现一对多)
<!-- 因为主要查询的是user 所以先配置User类的结果 --> <resultMap type="user" id="userOrderResultMap"> <!-- 第一步:配置User类的对应关系 --> <id property="id" column="id" /> <result property="username" column="username" /> <result property="sex" column="sex" /> <result property="address" column="address" /> <!-- 第二步:配置order类的对应关系 --> <!-- property:填写pojo类中集合类类属性的名称 javaType:填写集合类型的名称 ofType:list中内容的类型 --> <collection property="orders" javaType="list" ofType="order"> <!-- 配置主键,是关联Order的唯一标识 这里要注意oid 是因为下面select标签的sql中给order的id起了别名 叫做oid--> <id property="id" column="oid" /> <result property="number" column="number" /> <result property="createtime" column="createtime" /> <result property="note" column="note" /> </collection> </resultMap> <!-- 一对多关联,查询订单同时查询该用户下的订单 --> <select id="queryUserOrder" resultMap="userOrderResultMap"> SELECT a.id,a.username,a.address,a.sex,b.id oid,b.number,b.createtime,b.note from user a left join order b on a.id = b.user_id </select>
当然也有更多一级的一对多:collection中有collection和association,这里不多介绍。
多对多
业务场景:每个老师有多个学生,每个学生又有多个老师,此为多对多。用法如下:
1. 首先涉及到三张表:学生表(student)、教师表(teacher)、学生和教师关系表(tu_teach_rel)
public class Student{ //学生表原属性 private String id; private String name; private int age; private Gender gender; //学生表新加属性 private List<Teacher> teachers; //下面省略get和set方法 } public class Teacher{ //教师表原属性 private int id; private String name; private Gender gender; private Subject subject; private String degree; //教师表新加属性 private List<Student> students; //下面省略get和set方法 } public class stu_teach_rel{ //学生教师关系表 private int id; private int stu_id; private int teach_id; //这里不需要加东西 //下面省略get和set方法 }
2. mapper.xml配置文件
<mapper namespace="com.yihaomen.mybatis.dao.StudentMapper"> <resultMap id="studentMap" type="Student"> <id property="id" column="id" /> <result property="name" column="name" /> <result property="age" column="age" /> <result property="gender" column="gender" typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler" /> </resultMap> <resultMap id="collectionMap" type="Student" extends="studentMap"> <collection property="teachers" ofType="Teacher"> <id property="id" column="teach_id" /> <result property="name" column="tname"/> <result property="gender" column="tgender" typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler"/> <result property="subject" column="tsubject" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/> <result property="degree" column="tdegree" javaType="string" jdbcType="VARCHAR"/> </collection> </resultMap> <select id="selectStudents" resultMap="collectionMap"> SELECT s.id, s.name, s.gender, t.id teach_id, t.name tname, t.gender tgender, t.subject tsubject, t.degree tdegree FROM student s LEFT JOIN stu_teach_rel str ON s.id = str.stu_id LEFT JOIN teacher t ON t.id = str.teach_id </select> </mapper>
总结:
一对一可以通过<association>实现,一对多和多对多通过<collection>实现。
参考:
1. https://www.cnblogs.com/kenhome/p/7764398.html
2. https://blog.csdn.net/qq_42780864/article/details/81429114
3. https://blog.csdn.net/lks1139230294/article/details/88087470
4. https://www.jb51.net/article/126584.htm
持续更新!!!