关于Mybatis中resultMap的column和property属性究竟该怎么写?
4 个回答
一. 前言
最近我有学生出去面试,被问到 “Mybatis实体类的属性名和表中的字段名不一致该怎么处理?”,这其实是一个很经典的面试题,接下来我就为大家详细解析一下这道面试题。
二. 分析
2.1 实体类和字段名不一致所带来的后果
为了讲清楚这个问题,我们先来设计下面这样一个案例。
表的设计如下图所示:
实体类如下图所示:
mapper.xml文件如下所示:
根据主键查询TbAccount对象的方法,我们发现【只有数据库中的字段和实体类的属性名字对得上的字段,才能被查出来!】
那么以上的这个问题该怎么解决呢?我给大家提出了如下两种解决方案。
2.2 解决方案一:将resultType替换为resultMap
我们需要先在mapper.xml文件中创建resultMap。
然后在mapper.xml文件的select方法节点中,把resultType替换为resultMap。
再一次根据主键查询TbAccount对象的方法,我们此时会发现,即使【数据库的列名和实体类的属性名对不上的字段,也能查出来了】
2.3 解决方案二:配置下划线和驼峰的映射关系
第二种解决方案,首先要在mybatis核心配置文件中添加下划线和驼峰的映射配置。
然后把mapper.xml文件中select查询节点中的resultMap再恢复成resultType。
再一次根据主键查询TbAccount对象的方法,我们会发现【数据库的列名和实体类的属性名对不上的字段,此时依然能查出来】
三. 结语
以前也经常有学生问我,[既然实体类的属性名和数据库的列名对不上会有问题,那我们在创建实体类的时候,让实体类的属性名跟数据库的字段名保持一致不就解决问题了吗?]
其实这个事情是这样的,现在所有的公司对于Java变量的命名规范,和数据库列名的命名规范要求并不一致!Java的变量命名规范是驼峰命名法,数据库的列名命名规范是下划线区分单词命名法,这样Java实体类和数据库列名不一致就成了一种常态。
为了尽量避免这种不一致造成的问题,我们可以在进行项目开发时参照阿里巴巴的开发规约,如下图所示:
现在你知道这个面试题该怎么解决及回答了吗?如果你还有其他问题,可以在评论区给我留言哦。
最后分享一套JavaWeb视频,从零基础入门到项目实战,让你学习Java不迷茫!!!
如果喜欢的话,欢迎关注+点赞+收藏哦!
一、前言
❝ MyBatis 创建时的一个思想是:数据库不可能永远是你所想或所需的那个样子。 我们希望每个数据库都具备良好的第三范式或 BCNF 范式,可惜它们并不都是那样。 如果能有一种数据库映射模式,完美适配所有的应用程序,那就太好了,但可惜也没有。 而 ResultMap 就是 MyBatis 对这个问题的答案。
❞
二、ResultMap 的属性列表
属性 | 描述 |
---|---|
id | 当前命名空间中的一个唯一标识,用于标识一个结果映射。 |
type | 类的完全限定名, 或者一个类型别名(关于内置的类型别名,可以参考上面的表格)。 |
autoMapping | 如果设置这个属性,MyBatis 将会为本结果映射开启或者关闭自动映射。 这个属性会覆盖全局的属性 autoMappingBehavior。默认值:未设置(unset)。 |
extends | 可以继承其他resultMap的一些写好的属性 |
三、resultMap标签介绍
- 「constructor」 - 用于在实例化类时,注入结果到构造方法中
- 「idArg」 - ID 参数;标记出作为 ID 的结果可以帮助提高整体性能
- 「arg」 - 将被注入到构造方法的一个普通结果
- 「id」 – 一个 ID 结果;标记出作为 ID 的结果可以帮助提高整体性能
- 「result」 – 注入到字段或 JavaBean 属性的普通结果
- 「association」 – 一个复杂类型的关联;许多结果将包装成这种类型 嵌套结果映射 – 关联可以是 resultMap 元素,或是对其它结果映射的引用
- 「collection」 – 一个复杂类型的集合 嵌套结果映射 – 集合可以是 resultMap 元素,或是对其它结果映射的引用
- 「discriminator」 – 使用结果值来决定使用哪个 resultMap
- 「case」 – 基于某些值的结果映射 嵌套结果映射 – case 也是一个结果映射,因此具有相同的结构和元素;或者引用其它的结果映射
四、id & result标签参数详解
属性 | 描述 |
---|---|
「property」 | 映射到列结果的字段或属性。如果 JavaBean 有这个名字的属性(property),会先使用该属性。否则 MyBatis 将会寻找给定名称的字段(field)。 无论是哪一种情形,你都可以使用常见的点式分隔形式进行复杂属性导航。 「人话为:就是你的Java实体类」 |
「column」 | 「数据库中的列名」,或者是列的别名。一般情况下,这和传递给 resultSet.getString(columnName) 方法的参数一样。 |
javaType | 一个 Java 类的全限定名,或一个类型别名(关于内置的类型别名,可以参考上面的表格)。 如果你映射到一个 JavaBean,MyBatis 通常可以推断类型。然而,如果你映射到的是 HashMap,那么你应该明确地指定 javaType 来保证行为与期望的相一致。 |
「jdbcType」 | JDBC 类型,所支持的 JDBC 类型参见这个表格之后的“支持的 JDBC 类型”。 只需要在可能执行插入、更新和删除的且允许空值的列上指定 JDBC 类型。这是 JDBC 的要求而非 MyBatis 的要求。如果你直接面向 JDBC 编程,你需要对可以为空值的列指定这个类型。 |
typeHandler | 我们在前面讨论过默认的类型处理器。使用这个属性,你可以覆盖默认的类型处理器。 这个属性值是一个类型处理器实现类的全限定名,或者是类型别名。 |
「- 常用例子展示」
<resultMap id="UsersMap" type="com.wang.test.demo.entity.User">
<id property="id" column="id" jdbcType="INTEGER"/>
<result property="username" column="username" jdbcType="VARCHAR"/>
<result property="password" column="password" jdbcType="VARCHAR"/>
<result property="role" column="role" jdbcType="VARCHAR"/>
<result property="addTime" column="add_time" jdbcType="TIMESTAMP"/>
</resultMap>
五、association标签常用参数详解
属性 | 描述 |
---|---|
property | 「映射到列结果的字段或属性」。如果用来匹配的 JavaBean 存在给定名字的属性,那么它将会被使用。否则 MyBatis 将会寻找给定名称的字段。 无论是哪一种情形,你都可以使用通常的点式分隔形式进行复杂属性导航。 「人话为:你要一对一的实体类中的另一个实体类的名称」 |
javaType | 「一个 Java 类的完全限定名,或一个类型别名。」 如果你映射到一个 JavaBean,MyBatis 通常可以推断类型。然而,如果你映射到的是 HashMap,那么你应该明确地指定 javaType 来保证行为与期望的相一致。 |
「例子演示」
- 实体类演示
@Data
//书籍
public class Book {
private String id;
private String name;
private String author;
private Double price;
private Integer del;
private Date publishdate;
private String info;
//把出版社对象当作属性
private Publisher pub;//------重点在这里一本书对应一个出版社,这是一个出版社对象
}
@Data
//出版社
public class Publisher {
private String id;
private String name;
private String phone;
private String address;
}
「- xml演示」
<resultMap id="rMap_book" type="com.wang.test.demo.entity.Book">
<!-- 主键 property为实体类属性 column为数据库字段 jdbcType为实体类对应的jdbc类型-->
<id property="id" column="b_id" jdbcType="VARCHAR"></id>
<!-- 普通属性 property为实体类属性 column为数据库字段 jdbcType为实体类对应的jdbc类型-->
<result property="name" column="b_name" jdbcType="VARCHAR"></result>
<result property="author" column="author" jdbcType="VARCHAR"></result>
<result property="price" column="price" jdbcType="VARCHAR"></result>
<result property="del" column="del" jdbcType="NUMERIC"></result>
<result property="publisherid" column="publisher_id" jdbcType="VARCHAR"></result>
<result property="publishdate" column="publish_date" jdbcType="TIMESTAMP"></result>
<!--一对一映射association property 为实体类book中的属性名字 javaType为实体类属性的类型 -->
<association property="pub" javaType="com.wang.test.demo.entity.Publisher">
<id property="id" column="p_id" jdbcType="VARCHAR"></id>
<result property="name" column="name" jdbcType="VARCHAR"></result>
<result property="phone" column="phone" jdbcType="VARCHAR"></result>
<result property="address" column="address" jdbcType="VARCHAR"></result>
</association>
</resultMap>
六、collection标签常用参数详解
属性 | 描述 |
---|---|
property | 「映射到列结果的字段或属性」。如果用来匹配的 JavaBean 存在给定名字的属性,那么它将会被使用。否则 MyBatis 将会寻找给定名称的字段。 无论是哪一种情形,你都可以使用通常的点式分隔形式进行复杂属性导航。 「人话为:你要一对一的实体类中的另一个实体类的名称」 |
javaType | 这里和一对一的表示不太一样,「这里一般是一对多的集合类型」,如:list |
ofType | 指定的这个一对多的集合的所「存放的实体类的类型」 |
「例子演示」
「- 实体类演示」
@Data
//班级类
public class Class {
private String id;
private String name;
private List<Student> students;//----重点在这里,一个班级对应多个学生
}
@Data
public class Student {
private int id;
private String name;
private int age;
}
「- xml演示」
<resultMap id="rMap_class" type="com.wang.test.demo.entity.Class">
<id property="id" column="id" jdbcType="VARCHAR"></id>
<result property="name" column="name" jdbcType="VARCHAR"></result>
<!--一对多映射用这个 ofTyp是一对多的集合的所存放的实体类 javaType实体类的属性类型-->
<collection property="students" ofType="com.wang.test.demo.entity.Student" javaType="list">
<id property="id" column="id" jdbcType="INTEGER"></id>
<result property="name" column="name" jdbcType="VARCHAR"></result>
<result property="age" column="age" jdbcType="INTEGER"></result>
</collection>
</resultMap>
七、jdbc Type与java Type对照表
JDBC Type | Java Type |
---|---|
CHAR | String |
VARCHAR | String |
LONGVARCHAR | String |
NUMERIC | java.math.BigDecimal |
DECIMAL | java.math.BigDecimal |
BIT | boolean |
BOOLEAN | boolean |
TINYINT | byte |
SMALLINT | short |
INTEGER | INTEGER |
BIGINT | long |
REAL | float |
FLOAT | double |
DOUBLE | double |
BINARY | byte[] |
VARBINARY | byte[] |
LONGVARBINARY | byte[] |
DATE | java.sql.Date |
TIME | java.sql.Time |
TIMESTAMP | java.sql.Timestamp |
CLOB | Clob |
BLOB | Blob |
ARRAY | Array |
DISTINCT | mapping of underlying type |
STRUCT | Struct |
REF | Ref |
DATALINK | java.net.URL |
附:表格来源 |
八、总结
❝ 这样就对ResultMap具体参数进行详细的解释,还有对association和collection标签的解释和具体演示,希望能够帮到你,一起学习,如果用到收藏一下呗!!!!
❞