原文链接:这里
0.前言
总有一些奇葩的问题需要你去解决。mybatis中又遇到了一个resultMap,刚解决了resultType和parameterType。
1.属性说明
resultMap有一些属性
- id:resultMap标签的标识。
- type:返回值的全限定类名,或类型别名。
- autoMapping:值范围true(默认值)|false, 设置是否启动自动映射功能,自动映射功能就是自动查找与字段名小写同名的属性名,并调用setter方法。而设置为false后,则需要在
resultMap
内明确注明映射关系才会调用对应的setter方法。
2.用法1:SQL字段与实体属性映射
(1)问题来源
mybatis负责和mysql交互的时候,一般要求pojo实体类与数据库字段名一一对应。例如下面这个样子:
实体类:
package com.cat.pojo; import lombok.Data; @Data public class Students { private int id; private String stu_name; private String stu_sex; private int class_id; private int age; }XML文件:
<?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.cat.dao.StudentsMapper"> <!--展示所有学生--> <select id="listAllStudents" resultType="com.cat.pojo.Students"> select id ,stu_name ,class_id from students; </select> </mapper>一开始我们都这样操作,从数据库取出的数据可以和pojo中的实体类做到一一对应。当然,这是理想状态下,实际情况下可能会遇到很多不一致的情况。公司中可能有人单独写数据库,有人单独写后端,这个时候数据库字段名和后端的实体类中的属性名不一致很正常,比如:
pojo中实体类
package com.cat.pojo; import lombok.Data; @Data public class Students { private int uid; private String name; private String stu_sex; private int class_id; private int age; }xml的数据库映射文件:
<?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.cat.dao.StudentsMapper"> <!--展示所有学生--> <select id="listAllStudents" resultType="com.cat.pojo.Students"> select id ,stu_name ,class_id from students; </select> </mapper>在上面中,我们定义的实体类中的ID、name和数据库中的字段id、stu_name不一样。这个时候你执行查询语句,就会出现下面这样的结果:
数据库查询log显示:(前提你要安装相应的插件或启用相关功能,不然看不到数据库的log信息)
==> Preparing: select id ,stu_name ,class_id from students; ==> Parameters: <== Columns: id, stu_name, class_id <== Row: 1000, 张三, 1001 <== Row: 1001, 王晓红, 2001 <== Row: 1002, 李清乐, 1001 <== Row: 1003, 赵倚天, 3001 <== Row: 1004, 孙思淼, 3001 <== Row: 1005, 李思露, 2001 <== Row: 1006, 杨阳, 1001 <== Total: 7返回到程序中就变成:
[Students(uid=0, name=null, stu_sex=null, class_id=1001, age=0), Students(uid=0, name=null, stu_sex=null, class_id=2001, age=0), Students(uid=0, name=null, stu_sex=null, class_id=1001, age=0), Students(uid=0, name=null, stu_sex=null, class_id=3001, age=0), Students(uid=0, name=null, stu_sex=null, class_id=3001, age=0), Students(uid=0, name=null, stu_sex=null, class_id=2001, age=0), Students(uid=0, name=null, stu_sex=null, class_id=1001, age=0)]从上面中可以看出,如果我们实体类和数据库字段名不一致,数据库执行的sql语句并不能完整的映射到实体类中。
(2)解决办法1
数据库字段定义完了基本不会乱动了,可是我又不想改实体类怎么办。那就只能从配置下手了。我可以把XML文件改成下面这样:
<?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.cat.dao.StudentsMapper"> <!--展示所有学生--> <select id="listAllStudents" resultType="com.cat.pojo.Students"> select id as uid, stu_name as name, class_id from students; </select> </mapper>当使用as 时可以把 数据库字段名”当作“实体类属性名。这个时候,数据库查询的log显示如下:
==> Preparing: select id as uid, stu_name as name, class_id from students; ==> Parameters: <== Columns: uid, name, class_id <== Row: 1000, 张三, 1001 <== Row: 1001, 王晓红, 2001 <== Row: 1002, 李清乐, 1001 <== Row: 1003, 赵倚天, 3001 <== Row: 1004, 孙思淼, 3001 <== Row: 1005, 李思露, 2001 <== Row: 1006, 杨阳, 1001 <== Total: 7打印实体类显示的结果:
[Students(uid=1000, name=张三, stu_sex=null, class_id=1001, age=0), Students(uid=1001, name=王晓红, stu_sex=null, class_id=2001, age=0), Students(uid=1002, name=李清乐, stu_sex=null, class_id=1001, age=0), Students(uid=1003, name=赵倚天, stu_sex=null, class_id=3001, age=0), Students(uid=1004, name=孙思淼, stu_sex=null, class_id=3001, age=0), Students(uid=1005, name=李思露, stu_sex=null, class_id=2001, age=0), Students(uid=1006, name=杨阳, stu_sex=null, class_id=1001, age=0)]可以看出,这种方式可以做到数据库字段名和实体类属性名不一致的时候取数据的情况。
(3)解决办法2
上面的解法方法可以做到当数据库字段名和实体类名不一致的时候取数据的问题,但是我们也能看出,你的sql语句改变了,我现在不想改变sql语句,又想做到正常映射怎么办?这就用到了今天的主题:resultMap。
比如下面这样写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.cat.dao.StudentsMapper"> <resultMap id="getStudentByMap" type="com.cat.pojo.Students"> <result property="uid" column="id"></result> <result property="name" column="stu_name"></result> </resultMap> <select id="listAllStudents" resultMap="getStudentByMap"> select id ,stu_name,class_id from students; </select> </mapper>其中:
- id元素 ,用于设置主键字段与领域模型属性的映射关系
- result元素 ,用于设置普通字段与领域模型属性的映射关系
id、result语句属性配置细节:
属性 | 描述 |
property | 需要映射到JavaBean 的属性名称。 |
column | 数据表的列名或者标签别名。 |
javaType | 一个完整的类名,或者是一个类型别名。如果你匹配的是一个JavaBean,那MyBatis 通常会自行检测到。然后,如果你是要映射到一个HashMap,那你需要指定javaType 要达到的目的。 |
jdbcType | 数据表支持的类型列表。这个属性只在insert,update 或delete 的时候针对允许空的列有用。JDBC 需要这项,但MyBatis 不需要。如果你是直接针对JDBC 编码,且有允许空的列,而你要指定这项。 |
typeHandler | 使用这个属性可以覆写类型处理器。这项值可以是一个完整的类名,也可以是一个类型别名。 |
其他都不用改动,运行结果:
sql的log显示
==> Preparing: select id ,stu_name,class_id from students; ==> Parameters: <== Columns: id, stu_name, class_id <== Row: 1000, 张三, 1001 <== Row: 1001, 王晓红, 2001 <== Row: 1002, 李清乐, 1001 <== Row: 1003, 赵倚天, 3001 <== Row: 1004, 孙思淼, 3001 <== Row: 1005, 李思露, 2001 <== Row: 1006, 杨阳, 1001 <== Total: 7打印实体类显示:
[Students(uid=1000, name=张三, stu_sex=null, class_id=1001, age=0), Students(uid=1001, name=王晓红, stu_sex=null, class_id=2001, age=0), Students(uid=1002, name=李清乐, stu_sex=null, class_id=1001, age=0), Students(uid=1003, name=赵倚天, stu_sex=null, class_id=3001, age=0), Students(uid=1004, name=孙思淼, stu_sex=null, class_id=3001, age=0), Students(uid=1005, name=李思露, stu_sex=null, class_id=2001, age=0), Students(uid=1006, name=杨阳, stu_sex=null, class_id=1001, age=0)]可以看出,这样的方法也能够让数据库的字段名和实体类属性名做到对应,而且我们原来写好的sql文件就不用动了,当然也有人觉得麻烦,看个人喜好。