目录儿
一、结果映射(resultMap)
resultMap 元素有很多子元素:
constructor
- 用于在实例化类时,注入结果到构造方法中idArg
- ID 参数;标记出作为 ID 的结果可以帮助提高整体性能arg
- 将被注入到构造方法的一个普通结果
id
– 一个 ID 结果;标记出作为 ID 的结果可以帮助提高整体性能result
– 注入到字段或 JavaBean 属性的普通结果association
– 一个复杂类型的关联;许多结果将包装成这种类型- 嵌套结果映射 – 关联可以是 resultMap 元素,或是对其它结果映射的引用
collection
– 一个复杂类型的集合- 嵌套结果映射 – 集合可以是 resultMap 元素,或是对其它结果映射的引用
discriminator
– 使用结果值来决定使用哪个 resultMapcase
– 基于某些值的结果映射- 嵌套结果映射 – case 也是一个结果映射,因此具有相同的结构和元素;或者引用其它的结果映射
1.1 id & result结果映射元素
id
和result
是一个结果映射的最基础元素
<resultMap id="resultMapOne" type="Demo">
<id property="id" column="post_id"/>
<result property="subject" column="post_subject"/>
</resultMap>
id
和result
元素都是将一个列的值映射到一个简单数据类型(String, int, double, Date 等等)的属性或字段。- 这两者之间的唯一不同是,
id
元素对应的属性会被标记为对象的标识符,在比较对象实例时使用。 这样可以提高整体的性能,尤其是进行缓存和嵌套结果映射(也就是连接映射)的时候。
Id
和Result
元素的属性:
属性 | 描述 |
---|---|
property | 指定列结果映射的字段或属性。如果 JavaBean 有这个名字的属性如username ,就会把查询到的值映射到username 。还可以使用点式分隔形式进行复杂映射, 如映射到animal 属性的name 属性:animal.name 。 |
column | 表列名或列的别名。一般情况下,和用getter 方法给字段赋值一样。 |
javaType | 一个Java 类的全限定名,映射到一个JavaBean ,MyBatis通常可以推断类型。然而,如果你映射到的是HashMap ,应该明确地指定javaType 来保证行为与期望的相一致。 |
jdbcType | JDBC 类型,只需要在可能执行插入、更新和删除的且允许空值的列上指定 JDBC 类型。这是 JDBC 的要求而非 MyBatis 的要求。 |
typeHandler | 使用这个属性,可以覆盖默认的类型处理器。 这个属性值是一个类型处理器实现类的全限定名,或者是类型别名。 |
1.2 constructor构造器元素
有些情况下想使用不可变类,只在构造方法初始化时才能为类属性赋值,constructor 元素就是为此而生的。
public class User {
//...
public User(Integer id, String username, int age) {
//...
}
}
为了将结果注入构造方法,MyBatis 需要通过某种方式定位相应的构造方法,从版本 3.4.3 开始,可以在指定参数名称的前提下,以任意顺序编写 arg 元素。
<resultMap id="resultMapTwo" type="User">
<constructor>
<idArg column="id" javaType="int" name="id" />
<arg column="age" javaType="_int" name="age" />
<arg column="username" javaType="String" name="username" />
</constructor>
</resultMap>
1.3 association关联元素
association
元素用来处理关联或嵌套关系, 比如一个博客有一个用户。关联结果映射和其它类型的映射工作方式差不多。需要指定目标属性名以及属性的javaType(很多时候 MyBatis 可以自己推断出来)
属性 | 描述 |
---|---|
property | 指定列结果映射的字段或属性。如果 JavaBean 有这个名字的属性如username ,就会把查询到的值映射到username 。还可以使用点式分隔形式进行复杂映射, 如映射到animal 属性的name 属性:animal.name 。 |
javaType | 一个Java 类的全限定名,映射到一个JavaBean ,MyBatis通常可以推断类型。然而,如果你映射到的是HashMap ,应该明确地指定javaType 来保证行为与期望的相一致。 |
jdbcType | JDBC 类型,只需要在可能执行插入、更新和删除的且允许空值的列上指定 JDBC 类型。这是 JDBC 的要求而非 MyBatis 的要求。 |
typeHandler | 使用这个属性,可以覆盖默认的类型处理器。 这个属性值是一个类型处理器实现类的全限定名 |
column | 表列名或列的别名。一般情况下,和用getter 方法给字段赋值一样。 注意:在使用复合主键的时候,可以使用 column="{prop1=col1,prop2=col2}" 这样的语法来指定多个传递给嵌套 Select 查询语句的列名。这会使得 prop1 和 prop2 作为参数对象,被设置为对应嵌套 Select 语句的参数。 |
select | 子查询(嵌套查询)语句的 ID,它会把column 属性指定的列的检索数据,作为参数传递给目标select 语句。 |
fetchType | 可选的。有效值为 lazy 和 eager。 指定属性后,将在映射中忽略全局配置参数 lazyLoadingEnabled,使用属性的值。 |
resultMap | 结果映射的 ID,可以将此关联的嵌套结果集映射到一个合适的对象树中。 它可以作为使用额外 select 语句的替代方案。它可以将多表连接操作的结果映射成一个单一的 ResultSet。 |
1.3.1 嵌套结果映射
把查询出来的关联结果映射到属性的属性中,如下把作者相关的关联数据author_id
、author_username
映射到Author
属性的相关属性id
、username
中。
- 直接在< association >元素内指定映射关系。
<association property="author" column="blog_author_id" javaType="Author">
<id property="id" column="author_id"/>
<result property="username" column="author_username"/>
</association>
- 通过
resultMap
属性指定一个结果集
<select id="selectBlog" resultMap="blogResult">
select
B.id as blog_id,
B.title as blog_title,
B.author_id as blog_author_id,
A.id as author_id,
A.username as author_username,
A.password as author_password,
A.email as author_email,
A.bio as author_bio
from Blog B left outer join Author A on B.author_id = A.id
where B.id = #{id}
</select>
<resultMap id="blogResult" type="Blog">
<id property="id" column="blog_id" />
<result property="title" column="blog_title"/>
<association property="author" column="blog_author_id" javaType="Author" resultMap="authorResult"/>
</resultMap>
<resultMap id="authorResult" type="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"/>
</resultMap>
1.3.2 嵌套子查询
在结果映射中嵌套一个子查询,用column
属性指定一个或多个列字段作为参数,如author_id
,传递给用select
属性指定的id = selectAuthor
的查询语句去执行子查询并封装到javaType
属性指定的属性中。
<resultMap id="blogResult" type="Blog">
<id property="id" column="blog_id"/>
<result property="context" column="context"/>
<association property="author" column="author_id" javaType="Author" select="selectAuthor"/>
</resultMap>
<select id="selectBlog" resultMap="blogResult">
SELECT blog_id,context,author_id FROM BLOG WHERE blog_id = #{id}
</select>
<select id="selectAuthor" resultType="Author">
SELECT * FROM AUTHOR WHERE author_id = #{id}
</select>
1.3.3 嵌套多结果映射
这个关于resultSet
属性,暂时没用到,先不了解。
1.4 collection 集合元素
集合元素和关联元素几乎是一样的,相似的程度很高,直接上案例!
一个博客Blog
只有一个作者Author
,但一个博客有很多文章Post
。 在博客类中,这可以用下面的写法来表示:
private List<Post> posts;
要像上面这样,映射嵌套结果集合到一个List
中,可以使用集合元素。 和关联元素一样。可以使用嵌套Select
查询,或基于连接的嵌套结果映射集合。
1.4.1 嵌套子查询
<resultMap id="blogResult" type="Blog">
<collection property="posts" javaType="ArrayList" column="id" ofType="Post" select="selectPostsForBlog"/>
</resultMap>
<select id="selectBlog" resultMap="blogResult">
SELECT * FROM BLOG WHERE ID = #{id}
</select>
<select id="selectPostsForBlog" resultType="Post">
SELECT * FROM POST WHERE BLOG_ID = #{id}
</select>
仔细观察会注意到与关联元素对比,这个集合元素多了一个新的ofType
属性。这个属性非常重要,它用来将JavaBean
属性的类型和集合存储的类型区分开来。
所以语句:
<collection property="posts" javaType="ArrayList" column="id" ofType="Post" select="selectPostsForBlog"/>
读作: posts
是一个存储Post
的ArrayList
集合”
在一般情况下,MyBatis 可以推断javaType
属性,因此并不需要填写。所以很多时候你可以简略成:
<collection property="posts" column="id" ofType="Post" select="selectPostsForBlog"/>
用法与关联元素相似
<select id="selectBlog" resultMap="blogResult">
select
B.id as blog_id,
B.title as blog_title,
B.author_id as blog_author_id,
P.id as post_id,
P.subject as post_subject,
P.body as post_body,
from Blog B
left outer join Post P on B.id = P.blog_id
where B.id = #{id}
</select>
<resultMap id="blogResult" type="Blog">
<id property="id" column="blog_id" />
<result property="title" column="blog_title"/>
<collection property="posts" ofType="Post">
<id property="id" column="post_id"/>
<result property="subject" column="post_subject"/>
<result property="body" column="post_body"/>
</collection>
</resultMap>
二、其他例子
1 结果对象中包含类似 List< String > 这样的集合
模型
public class DesktopGroup {
private Long id;
private String name;
@TableField(exist = false)
private List<String> vmIds;
}
mapper
<resultMap id="baseMapWithVmids" type="com.wipinfo.central.engine.entity.DesktopGroup">
<id column="id" property="id" jdbcType="VARCHAR"/>
<result column="name" property="name" jdbcType="VARCHAR"/>
<!--
集合填充对象 property="vmIds"
数据类型 ofType="java.lang.String"
-->
<collection property="vmIds" ofType="java.lang.String">
<!-- 查询列 column="desk_id" ,因为是 String 类型,所以没有 property 属性 -->
<result column="desk_id"/>
</collection>
</resultMap>
<select id="selectListWithVmIds" resultMap="baseMapWithVmids">
select id,name,desk_id
FROM aaa_jdbc.t_wipinfo_engine_desktopgroups d
INNER JOIN aaa_jdbc.t_wipinfo_engine_desk_group dg
ON d."id" = dg.group_id
</select>