java版云笔记(八)之关联映射
来源:互联网 发布:电子文档软件 编辑:程序博客网 时间:2024/04/30 06:22
Mybatis关联映射
通过数据库对象之间的关联关系,反映到到实体对象之间的引用。
加载多个表中的关联数据,封装到我们的实体对象中。
当业务对数据库进行关联查询。
关联
<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 映射语句来返回预期的复杂类型。
嵌套结果:使用嵌套结果映射来处理重复的联合结果的子集。首先,然让我们来查看这个元素的属性。所有的你都会看到,它和普通的只由 select 和
resultMap 属性的结果映射不同。
关联的嵌套查询
示例:
<resultMap id="blogResult" type="Blog"> <!-- property映射到读者实体类 --> <association property="author" column="author_id" javaType="Author" select="selectAuthor"/></resultMap><select id="selectBlog" resultMap="blogResult"> SELECT * FROM BLOG WHERE ID = #{id}</select><select id="selectAuthor" resultType="Author"> SELECT * FROM AUTHOR WHERE ID = #{id}</select>
我们有两个查询语句:一个来加载博客,另外一个来加载作者,而且博客的结果映射描述了“selectAuthor”语句应该被用来加载它的 author 属性。 其他所有的属性将会被自动加载,假设它们的列和属性名相匹配。
这种方式很简单, 但是对于大型数据集合和列表将不会表现很好。问题就是我们熟知的 “N+1 查询问题”。概括地讲,N+1 查询问题可以是这样引起的:
你执行了一个单独的 SQL 语句来获取结果列表(就是“+1”)。
对返回的每条记录,你执行了一个查询语句来为每个加载细节(就是“N”)。
这个问题会导致成百上千的 SQL 语句被执行。这通常不是期望的。MyBatis 能延迟加载这样的查询就是一个好处,因此你可以分散这些语句同时运行的消耗。然而,如果你加载一个列表,之后迅速迭代来访问嵌套的数据,你会调用所有的延迟加载,这样的行为可能是很糟糕的。
所以还有另外一种方法。
关联的嵌套结果
在上面你已经看到了一个非常复杂的嵌套关联的示例。下面这个是一个非常简单的示例来说明它如何工作。代替了执行一个分离的语句,我们联合博客表和作者表在一起,就像:
<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>
非常重要: id元素在嵌套结果映射中扮演着非常重要的角色。你应该总是指定一个或多个可以唯一标识结果的属性。实际上如果你不指定它的话, MyBatis仍然可以工作,但是会有严重的性能问题。在可以唯一标识结果的情况下, 尽可能少的选择属性。主键是一个显而易见的选择(即使是复合主键)。
现在,上面的示例用了外部的结果映射元素来映射关联。这使得 Author 结果映射可以重用。然而,如果你不需要重用它的话,或者你仅仅引用你所有的结果映射合到一个单独描述的结果映射中。你可以嵌套结果映射。
这里给出使用这种方式的相同示例(嵌套结果映射):
<resultMap id="blogResult" type="Blog"> <id property="id" column="blog_id" /> <result property="title" column="blog_title"/> <association property="author" javaType="Author" javaType="Author" select="authorResult"> <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> <!--select的值和id的值要一样 --> <select id="authorResult" resultType="Author"> <!-- sql语句 ---> </select> <!-- resultMap的id和resultMap值一样 --> <select id="getById" parameterType="int" resultMap="blogResult" > <!-- sql语句 ---> </select>
如果blog有一个co-author怎么办? select语句将看起来这个样子
<select id="selectBlog" resultMap="blogResult"> select B.id as blog_id, B.title as blog_title, 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, CA.id as co_author_id, CA.username as co_author_username, CA.password as co_author_password, CA.email as co_author_email, CA.bio as co_author_bio from Blog B left outer join Author A on B.author_id = A.id left outer join Author CA on B.co_author_id = CA.id where B.id = #{id}</select>
因为结果中的列名与resultMap中的列名不同。 你需要指定columnPrefix去重用映射co-author结果的resultMap。
<resultMap id="blogResult" type="Blog"> <id property="id" column="blog_id" /> <result property="title" column="blog_title"/> <association property="author" resultMap="authorResult" /> <association property="coAuthor" resultMap="authorResult" columnPrefix="co_" /></resultMap>
集合
<collection property="posts" ofType="domain.blog.Post"> <id property="id" column="post_id"/> <result property="subject" column="post_subject"/> <result property="body" column="post_body"/> </collection>
集合元素的作用几乎和关联是相同的。实际上,它们也很相似,文档的异同是多余的。所以我们更多关注于它们的不同。
我们来继续上面的示例,一个博客只有一个作者。但是博客有很多文章。在博客类中, 这可以由下面这样的写法来表示:
private List<Post> posts;
要映射嵌套结果集合到 List 中,我们使用集合元素。就像关联元素一样,我们可以从连接中使用嵌套查询,或者嵌套结果。
集合的嵌套查询
首先,让我们看看使用嵌套查询来为博客加载文章
<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"/>
读作: “在 Post 类型的 ArrayList 中的 posts 的集合。”
javaType 属性是不需要的,因为 MyBatis 在很多情况下会为你算出来。所以你可以缩短写法:
<collection property="posts" column="id" ofType="Post" select="selectPostsForBlog"/>
集合的嵌套结果
至此,你可以猜测集合的嵌套结果是如何来工作的,因为它和关联完全相同,除了它应用了一个“ofType”属性
首先,让我们看一下SQL:
<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>
同样,要记得 id 元素的重要性,如果你不记得了,请阅读上面的关联部分。
同样, 如果你引用更长的形式允许你的结果映射的更多重用, 你可以使用下面这个替代的映射:
<resultMap id="blogResult" type="Blog"> <id property="id" column="blog_id" /> <result property="title" column="blog_title"/> <collection property="posts" ofType="Post" resultMap="blogPostResult" columnPrefix="post_"/> </resultMap> <resultMap id="blogPostResult" type="Post"> <id property="id" column="id"/> <result property="subject" column="subject"/> <result property="body" column="body"/> </resultMap>
注意 :这个对你所映射的内容没有深度,广度或关联和集合相联合的限制。当映射它们时你应该在大脑中保留它们的表现。你的应用在找到最佳方法前要一直进行的单元测试和性能测试。好在 myBatis 让你后来可以改变想法,而不对你的代码造成很小(或任何)影响。
- java版云笔记(八)之关联映射
- hibernate笔记(八)一对一关联映射分析
- 【SSH进阶之路】Hibernate映射——多对多关联映射(八)
- 【SSH进阶之路】Hibernate映射——多对多关联映射(八)
- 【SSH进阶之路】Hibernate映射——多对多关联映射(八)
- 【SSH进阶之路】Hibernate映射——多对多关联映射(八)
- 【SSH进阶之路】Hibernate映射——多对多关联映射(八)
- 【Hibernate】(八)关联映射之多对多映射
- JavaEE经典试题(八)Hibernate实体关联映射
- C++ Primer笔记(八)关联容器
- hibernate关联映射笔记
- Hibernate之关联映射(上)
- Hibernate之关联映射(下)
- 初识Hibernate之关联映射(一)
- 初识Hibernate之关联映射(二)
- 初识Hibernate之关联映射(二)
- 初识Hibernate之关联映射(一)
- MyBatis之关联映射
- 《第一行代码》(2)整理读后笔记
- 201710032355->使用静态方法记录窗体加载
- bzoj2761 [JLOI2011]不重复数字
- Spark开发-RDD接口编程
- MyBatis映射器使用注意事项
- java版云笔记(八)之关联映射
- Java编程思想读书笔记——多态
- Tensorflow实战Google-第五章mnist数字识别
- SpringBoot--5分钟搭建的微服务
- dede在高级搜索页面advancedsearch.php调用自定义字段
- 处理数据(一)
- opencv单目标跟踪
- gcc简介及常用编译选项
- dede advancedsearch.htm 头部,尾部标签无法识别! 无法识别channel 或者 channelartlist