myBatis3之SQL映射的XML文件(resultMap元素之五)
----------
高级结果映射之association元素(关联)
<association property="author" column="blog_author_id" javaType=" Author"> <id property="id" column="author_id"/> <result property="username" column="author_username"/> </association>
关联元素处理“有一个”类型的关系。比如,在我们的示例中,一个博客有一个用户。关联映射就工作于这种结果之上。你指定了目标属性,来获取值的列,属性的java类型(很多情况下MyBatis可以自己算出来),如果需要的话还有jdbc类型,如果你想覆盖或获取的结果值还需要类型控制器。关联中不同的是你需要告诉MyBatis如何加载关联。MyBatis在这方面会有两种不同的方式:
嵌套查询:通过执行另外一个SQL映射语句来返回预期的复杂类型。
嵌套结果:使用嵌套结果映射来处理重复的联合结果的子集。
首先,然让我们来查看这个元素的属性。所有的你都会看到。
属性 | 描述 |
property | 映射到列结果的字段或属性。如果匹配的是存在的,和给定名称相同的JavaBeans 的属性,那么就会使用。 否则MyBatis将会寻找给定名称的字段。这两种情形你可以使用通常点式的复杂属性导航。比如,你可以这样映射一 些 东 西 :“ username ”, 或 者 映 射 到 一 些 复 杂 的 东 西 :“address.street.number” |
column | 来自数据库的列名 , 或重命名的列标签 。 这和通常传递给resultSet.getString(columnName)方法的字符串是相同的。注意:要处理复合主键,你可以指定多个列名通过column=”{prop1=col1,prop2=col2}” 这种语法来传递给嵌套查询语句。这会引起prop1 和 prop2 以参数对象形式来设置给目标嵌套查询语句。 |
javaType | 一个 Java 类的完全限定名,或一个类型别名(参加上面内建类型别名的列表)。如果你映射到一JavaBean ,MyBatis通常可以断定类型。然而,如果你映射到的是HashMap,那么你应该明确地指定javaType 来保证所需的行为。 |
jdbcType | 在这个表格之前的所支持的JDBC类型列表中的类型。JDBC类型是仅仅需要对插入,更新和删除操作可能为空的列进行处理。。这是JDBC 的需要,而不是 MyBatis 的。如果你直接使用JDBC 编程,你需要指定这个类型-但仅仅对可能为空的值。 |
typeHandler | 我们在前面讨论过默认的类型处理器。使用这个属性,你可以覆盖默认的类型处理器。这个属性值是类的完全限定名或者是一个类型处理器的实现,或者是类型别名 |
select | 另外一个映射语句的 ID,可以加载这个属性映射需要的复杂类型。获取的在列属性中指定的列的值将被传递给目标select 语句作为参数。表格后面有一个详细的示例。 注意:要处理复合主键,你可以指定多个列名通过 column=”{prop1=col1,prop2=col2}”这种语法来传递给嵌套查询语句。这会引起prop1 和 prop2 以参数对象形式来设置给目标嵌套查询语句。 |
示例:
<resultMap id=”blogResult” type=”Blog”> <association property="author" column="blog_author_id" javaType="Author" select=”selectAuthor”/> </resultMap> <select id=”selectBlog” parameterType=”int” resultMap=”blogResult”> SELECT * FROM BLOG WHERE ID = #{id} </select> <select id=”selectAuthor” parameterType=”int” resultType="Author"> SELECT * FROM AUTHOR WHERE ID = #{id} </select>
我们有两个查询语句:一个来加载博客,另外一个来加载作者,而且博客的结果映射描述了“selectAuthor”语句应该被用来加载它的author属性。 其他所有的属性将会被自动加载,假设它们的列和属性名相匹配。 这种方式很简单,但是对于大型数据集合和列表将不会表现很好。问题就是我们熟知的N+1查询问题”。概括地讲,N+1查询问题可以是这样引起的:
1.你执行了一个单独的SQL语句来获取结果列表(就是“+1”)。
2.对返回的每条记录,你执行了一个查询语句来为每个加载细节(就是“N”)。
这个问题会导致成百上千的SQL语句被执行。这通常不是期望的。
MyBatis能延迟加载这样的查询就是一个好处,因此你可以分散这些语句同时运行的消耗。然而,如果你加载一个列表,之后迅速迭代来访问嵌套的数据,你会调用所有的延迟加载,这样的行为可能是很糟糕的。 所以还有另外一种方法。
关联的嵌套结果
resultMap | 这是结果映射的 ID,可以映射关联的嵌套结果到一个合适的对象图中。这是一种替代方法来调用另外一个查询语句。这允许你联合多个表来合成到一个单独的结果集。这样的结果集可能包含重复,数据的重复组需要被分解,合理映射到一个嵌套的对象图。为了使它变得容易,MyBat is 让你“链接”结果映射,来处理嵌套结果。 |
下面这个是一个非常简单的示例来说明它如何工作。代替了执行一个分离的语句,我们联合博客表和作者表在一起,就像:
<select id="selectBlog" parameterType="int" 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=”blog_id” column="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>
非常重要:在嵌套映射中 id元素扮演了非常重要的角色。应该通常指定一个或多个属性,它们可以用来唯一标识结果。实际上就是如果你离开她了,MyBatis仍然可以工作。选择的属性越少越好,它们可以唯一地标识结果。主键就是一个显而易见的选择(尽管是联合主键)。 现在,上面的示例用了外部的结果映射元素来映射关联。这使得Author结果映射可以重用。然而,如果你不需要重用它的话,你可以嵌套结果映射。
这里给出使用这种方式的相同示例:
<resultMap id="blogResult" type="Blog"> <id property=”blog_id” column="id" /> <result property="title" column="blog_title"/> <association property="author" column="blog_author_id" 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"/> </association> </resultMap>
上面你已经看到了如何处理“有一个”类型关联。但是“有很多个”是怎样的?见下一篇。