本文已参与「新人创作礼」活动,一起开启掘金创作之路。
简单的结果映射
一般情况下,结果映射我们可以使用默认的resultType="map",不需要去显示的指定结果类型。
<select id="getOne" resultType="map">
select * from user where id = #{id}
</select>
大部分情况下都够用,但是 HashMap 并不是一个很好的领域模型。我们更可能会使用 JavaBean 或 POJO(Plain Old Java Objects,普通老式 Java 对象)作为领域模型。
比如建一个实体,然后把字段作为结果映射到实体字段里:
<select id="getOne" resultType="com.xing.entity.UserEntity">
select * from user where id = #{id}
</select>
这个实体我们还可以使用类型别名标签,避免每次使用都用全类名
(类的全限定名):
<typeAlias type="com.xing.entity.UserEntity" alias="User"/>
<select id="getOne" resultType="User">
select * from user where id = #{id}
</select>
MyBatis 会自动创建一个 ResultMap,再根据属性名来映射列到 JavaBean 的属性上。如果列名和属性名不能匹配上,可以在 SELECT 语句中设置列别名(这是一个基本的 SQL 特性)来完成匹配。比如:
<select id="selectUsers" resultType="User">
select
user_id as "id",
user_name as "userName",
hashed_password as "hashedPassword"
from some_table
where id = #{id}
</select>
上面的例子没有一个需要显式配置 ResultMap,这就是 ResultMap 的优秀之处:你完全可以不用显式地配置它们,约定大于配置。
如果要将上面的ResultMap显示配置,这么写:
<resultMap id="userResultMap" type="User">
<id property="id" column="user_id" />
<result property="username" column="user_name"/>
<result property="password" column="hashed_password"/>
</resultMap>
然后在引用它的语句中设置 resultMap 属性就行了(注意我们去掉了 resultType 属性)。比如:
<select id="selectUsers" resultMap="userResultMap">
select user_id, user_name, hashed_password
from some_table
where id = #{id}
</select>
高级结果映射(比如多表联查)
这玩意在几年前用过后再没用过,懒得看,就是resultMap各种子元素的使用,有兴趣的可以去官网看看。
<resultMap id="detailedBlogResultMap" type="Blog">
<constructor>
<idArg column="blog_id" javaType="int"/>
</constructor>
<result property="title" column="blog_title"/>
<association property="author" javaType="Author">
<id property="id" column="author_id"/>
<result property="username" column="author_username"/>
<result property="password" column="author_password"/>
<result property="email" column="author_email"/>
<result property="bio" column="author_bio"/>
<result property="favouriteSection" column="author_favourite_section"/>
</association>
<collection property="posts" ofType="Post">
<id property="id" column="post_id"/>
<result property="subject" column="post_subject"/>
<association property="author" javaType="Author"/>
<collection property="comments" ofType="Comment">
<id property="id" column="comment_id"/>
</collection>
<collection property="tags" ofType="Tag" >
<id property="id" column="tag_id"/>
</collection>
<discriminator javaType="int" column="draft">
<case value="1" resultType="DraftPost"/>
</discriminator>
</collection>
</resultMap>
还有支持的JDBC的类型,这个还是比较常用的。
自动映射
可以通过在结果映射上设置 autoMapping 属性来为指定的结果映射设置启用/禁用自动映射。
<resultMap id="userResultMap" type="User" autoMapping="false">
# 这里可以不一一手动映射每个字段啦,当然也可以映射个别特殊字段
...
</resultMap>
mybatis判断某个resultMap是否开启自动映射配置的时候,会先查找自身的autoMapping属性,如果这个属性设置值了,就直接用这个属性的值,如果resultMap元素的autoMapping属性没有配置,则走全局配置的自动映射规则。
当自动映射查询结果时,MyBatis 会获取结果中返回的列名并在 Java 类中查找相同名字的属性(忽略大小写)。这意味着如果发现了 ID 列和 id 属性,MyBatis 会将列 ID 的值赋给 id 属性。
通常数据库列使用大写字母组成的单词命名,单词间用下划线分隔;而 Java 属性一般遵循驼峰命名法约定。为了在这两种命名方式之间启用自动映射,需要将 mapUnderscoreToCamelCase 设置为 true。
mybatis:
configuration:
map-underscore-to-camel-case: true
甚至在提供了结果映射后,自动映射也能工作。在这种情况下,对于每一个结果映射,在 ResultSet 出现的列,如果没有设置手动映射,将被自动映射。在自动映射处理完毕后,再处理手动映射。在下面的例子中,id 和 userName 列将被自动映射,hashed_password 列将根据配置进行映射。
<select id="selectUsers" resultMap="userResultMap">
select
user_id as "id",
user_name as "userName",
hashed_password
from some_table
where id = #{id}
</select>
全局配置
<resultMap id="userResultMap" type="User">
<result property="password" column="hashed_password"/>
</resultMap>
或者
<settings>
<!-- 关闭自动映射开关 -->
<setting name="autoMappingBehavior" value="NONE"/>
</settings>
有三种自动映射等级:
NONE - 禁用自动映射。仅对手动映射的属性进行映射。
PARTIAL - 对除在内部定义了嵌套结果映射(也就是连接的属性)以外的属性进行映射
FULL - 自动映射所有属性。
autoMappingBehavior值来源于枚举:
org.apache.ibatis.session.AutoMappingBehavior
全局配置:
<settings>
<!-- 关闭自动映射开关 -->
<setting name="autoMappingBehavior" value="NONE"/>
</settings>
默认值是 PARTIAL,这是有原因的。当对连接查询的结果使用 FULL 时,连接查询会在同一行中获取多个不同实体的数据,因此可能导致非预期的映射。下面的例子将展示这种风险:
<select id="selectBlog" resultMap="blogResult">
select
B.id,
B.title,
A.username,
from Blog B left outer join Author A on B.author_id = A.id
where B.id = #{id}
</select>
<resultMap id="blogResult" type="Blog">
<association property="author" resultMap="authorResult"/>
</resultMap>
<resultMap id="authorResult" type="Author">
<result property="username" column="author_username"/>
</resultMap>
在该结果映射中,Blog 和 Author 均将被自动映射。但是注意 Author 有一个 id 属性,在 ResultSet 中也有一个名为 id 的列,所以 Author 的 id 将填入 Blog 的 id,这可不是你期望的行为。所以,要谨慎使用 FULL。
总结:
一般情况下只需要简单映射即可,也可以使用自动映射,然后个别特殊字段手动映射。
建议可以去官网学习下。。。
END