mybatis的关联查询

Myth丶恋晨 2022-09-26 03:53 273阅读 0赞

三张表:user article blog

表的存储sql文件:

ExpandedBlockStart.gif

复制代码

  1. /*
  2. Navicat MySQL Data Transfer
  3. Source Server : localhost
  4. Source Server Version : 50620
  5. Source Host : localhost:3306
  6. Source Database : mybatis
  7. Target Server Type : MYSQL
  8. Target Server Version : 50620
  9. File Encoding : 65001
  10. Date: 2014-10-19 18:27:31
  11. */
  12. SET FOREIGN_KEY_CHECKS=0;
  13. -- ----------------------------
  14. -- Table structure for `user`
  15. -- ----------------------------
  16. DROP TABLE IF EXISTS `user`;
  17. CREATE TABLE `user` (
  18. `id` int(11) NOT NULL AUTO_INCREMENT,
  19. `userName` varchar(50) DEFAULT NULL,
  20. `userAge` int(11) DEFAULT NULL,
  21. `userAddress` varchar(200) DEFAULT NULL,
  22. PRIMARY KEY (`id`)
  23. ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
  24. -- ----------------------------
  25. -- Records of user
  26. -- ----------------------------
  27. INSERT INTO `user` VALUES ('1', 'summer', '30', 'shanghai');
  28. INSERT INTO `user` VALUES ('2', 'test1', '22', 'suzhou');
  29. INSERT INTO `user` VALUES ('3', 'test1', '29', 'some place');
  30. INSERT INTO `user` VALUES ('4', 'lu', '28', 'some place');
  31. INSERT INTO `user` VALUES ('5', 'xiaoxun', '27', 'nanjing');
  32. -- ----------------------------
  33. -- Table structure for `article`
  34. -- ----------------------------
  35. DROP TABLE IF EXISTS `article`;
  36. CREATE TABLE `article` (
  37. `id` int(11) NOT NULL AUTO_INCREMENT,
  38. `userid` int(11) NOT NULL,
  39. `title` varchar(100) DEFAULT NULL,
  40. `content` text,
  41. `blogid` int(11) NOT NULL,
  42. PRIMARY KEY (`id`)
  43. ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
  44. -- ----------------------------
  45. -- Records of article
  46. -- ----------------------------
  47. INSERT INTO `article` VALUES ('1', '1', 'test_title_1', 'test_content_1', '1');
  48. INSERT INTO `article` VALUES ('2', '1', 'test_title_2', 'test_content_2', '1');
  49. INSERT INTO `article` VALUES ('3', '1', 'test_title_3', 'test_content_3', '2');
  50. INSERT INTO `article` VALUES ('4', '1', 'test_title_4', 'test_content_4', '2');
  51. INSERT INTO `article` VALUES ('5', '2', 'test_title_5', 'test_content_5', '2');
  52. -- ----------------------------
  53. -- Table structure for `blog`
  54. -- ----------------------------
  55. DROP TABLE IF EXISTS `blog`;
  56. CREATE TABLE `blog` (
  57. `id` int(11) NOT NULL AUTO_INCREMENT,
  58. `title` varchar(200) DEFAULT NULL,
  59. PRIMARY KEY (`id`)
  60. ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
  61. -- ----------------------------
  62. -- Records of blog
  63. -- ----------------------------
  64. INSERT INTO `blog` VALUES ('1', 'xiaoxun_blog');
  65. INSERT INTO `blog` VALUES ('2', 'zhang_blog');

复制代码

配置文件Configuration.xml

复制代码

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  3. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  4. <configuration>
  5. <!-- mybatis别名定义 -->
  6. <typeAliases>
  7. <typeAlias alias="User" type="com.mybatis.test.User"/>
  8. <typeAlias alias="Article" type="com.mybatis.test.Article"/>
  9. <typeAlias alias="Blog" type="com.mybatis.test.Blog"/>
  10. </typeAliases>
  11. <environments default="development">
  12. <environment id="development">
  13. <transactionManager type="JDBC"/>
  14. <dataSource type="POOLED">
  15. <property name="driver" value="com.mysql.jdbc.Driver"/>
  16. <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis" />
  17. <property name="username" value="root"/>
  18. <property name="password" value="admin"/>
  19. </dataSource>
  20. </environment>
  21. </environments>
  22. <!-- mybatis的mapper文件,每个xml配置文件对应一个接口 -->
  23. <mappers>
  24. <mapper resource="com/mybatis/test/User.xml"/>
  25. <mapper resource="com/mybatis/test/Article.xml"/>
  26. <mapper resource="com/mybatis/test/Blog.xml"/>
  27. </mappers>
  28. </configuration>

复制代码

User类的定义和User.xml的配置见上一文章。

Article类定义:

ExpandedBlockStart.gif

复制代码

  1. package com.mybatis.test;
  2. public class Article {
  3. private int id;
  4. private User user;
  5. private String title;
  6. private String content;
  7. public int getId() {
  8. return id;
  9. }
  10. public void setId(int id) {
  11. this.id = id;
  12. }
  13. public User getUser() {
  14. return user;
  15. }
  16. public void setUser(User user) {
  17. this.user = user;
  18. }
  19. public String getTitle() {
  20. return title;
  21. }
  22. public void setTitle(String title) {
  23. this.title = title;
  24. }
  25. public String getContent() {
  26. return content;
  27. }
  28. public void setContent(String content) {
  29. this.content = content;
  30. }
  31. }

复制代码

Article类中有一个User类。

Article.xml的配置:

复制代码

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  3. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  4. <mapper namespace="com.mybatis.test.IArticleOperation">
  5. <resultMap type="User" id="userResultMap">
  6. <!-- 属性名和数据库列名映射 -->
  7. <id property="id" column="user_id" />
  8. <result property="userName" column="user_userName" />
  9. <result property="userAge" column="user_userAge" />
  10. <result property="userAddress" column="user_userAddress" />
  11. </resultMap>
  12. <!-- User join Article进行联合查询 (一对一)-->
  13. <resultMap id="articleResultMap" type="Article">
  14. <id property="id" column="article_id" />
  15. <result property="title" column="article_title" />
  16. <result property="content" column="article_content" />
  17. <!-- 将article的user属性映射到userResultMap -->
  18. <association property="user" javaType="User" resultMap="userResultMap"/>
  19. </resultMap>
  20. <!-- 使用别名来映射匹配 -->
  21. <select id="getUserArticles" parameterType="int" resultMap="articleResultMap">
  22. select user.id user_id,user.userName user_userName,user.userAddress user_userAddress,
  23. article.id article_id,article.title article_title,article.content article_content
  24. from user,article
  25. where user.id=article.userid and user.id=#{id}
  26. </select>
  27. <!-- 另一种联合查询 (一对一)的实现,但是这种方式有“N+1”的问题 -->
  28. <!-- <resultMap id="articleResultMap" type="Article">
  29. <id property="id" column="article_id" />
  30. <result property="title" column="article_title" />
  31. <result property="content" column="article_content" />
  32. <association property="user" javaType="User" column="userid" select="selectUser"/>
  33. </resultMap>
  34. <select id="selectUser" parameterType="int" resultType="User">
  35. select * from user where id = #{id}
  36. </select> -->
  37. </mapper>

复制代码

Blog类定义:

ExpandedBlockStart.gif

复制代码

  1. package com.mybatis.test;
  2. import java.util.List;
  3. public class Blog {
  4. private int id;
  5. private String title;
  6. private List<Article> articles;
  7. public int getId() {
  8. return id;
  9. }
  10. public void setId(int id) {
  11. this.id = id;
  12. }
  13. public String getTitle() {
  14. return title;
  15. }
  16. public void setTitle(String title) {
  17. this.title = title;
  18. }
  19. public List<Article> getArticles() {
  20. return articles;
  21. }
  22. public void setArticles(List<Article> articles) {
  23. this.articles = articles;
  24. }
  25. }

复制代码

Blog类中有一个List

Blog.xml配置:

复制代码

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  3. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  4. <mapper namespace="com.mybatis.test.IBlogOperation">
  5. <resultMap id="userResultMap" type="User">
  6. <id property="id" column="user_id" />
  7. <result property="userName" column="user_userName" />
  8. <result property="userAge" column="user_userAge" />
  9. <result property="userAddress" column="user_userAddress" />
  10. </resultMap>
  11. <resultMap id="articleResultMap" type="Article">
  12. <id property="id" column="article_id" />
  13. <result property="title" column="article_title" />
  14. <result property="content" column="article_content" />
  15. <association property="user" javaType="User" resultMap="userResultMap"/>
  16. </resultMap>
  17. <resultMap id="blogResultMap" type="Blog">
  18. <id property="id" column="blog_id" />
  19. <result property="title" column="blog_title" />
  20. <!-- 将article list属性映射到collection -->
  21. <collection property="articles" ofType="Article" resultMap="articleResultMap"/>
  22. </resultMap>
  23. <!-- select语句 -->
  24. <select id="getBlogByID" parameterType="int" resultMap="blogResultMap">
  25. select user.id user_id,user.userName user_userName,user.userAddress user_userAddress,
  26. article.id article_id,article.title article_title,article.content article_content,
  27. blog.id blog_id, blog.title blog_title
  28. from user,article,blog
  29. where user.id=article.userid and blog.id=article.blogid and blog.id=#{id}
  30. </select>
  31. </mapper>

复制代码

IArticleOperation定义:

复制代码

  1. package com.mybatis.test;
  2. import java.util.List;
  3. public interface IArticleOperation {
  4. public List<Article> getUserArticles(int userID);
  5. }

复制代码

IBlogOperation定义:

复制代码

  1. package com.mybatis.test;
  2. public interface IBlogOperation {
  3. Blog getBlogByID(int id);
  4. }

复制代码

Test类:

ExpandedBlockStart.gif

复制代码

  1. package com.mybatis.test;
  2. import java.io.Reader;
  3. import java.util.List;
  4. import org.apache.ibatis.io.Resources;
  5. import org.apache.ibatis.session.SqlSession;
  6. import org.apache.ibatis.session.SqlSessionFactory;
  7. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
  8. public class Test {
  9. private static SqlSessionFactory sqlSessionFactory;
  10. private static Reader reader;
  11. static {
  12. try {
  13. //通过配置文件初始化sqlSessionFactory
  14. reader = Resources.getResourceAsReader("Configuration.xml");
  15. sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
  16. } catch (Exception e) {
  17. e.printStackTrace();
  18. }
  19. }
  20. public static SqlSessionFactory getSession() {
  21. return sqlSessionFactory;
  22. }
  23. public void getUserByID(int userID) {
  24. SqlSession session = sqlSessionFactory.openSession();
  25. try {
  26. IUserOperation userOperation = session
  27. .getMapper(IUserOperation.class);
  28. User user = userOperation.selectUserByID(userID);
  29. if (user != null) {
  30. System.out.println(user.getId() + ":" + user.getUserName()
  31. + ":" + user.getUserAddress());
  32. }
  33. } finally {
  34. session.close();
  35. }
  36. }
  37. public void getUserList(String userName) {
  38. SqlSession session = sqlSessionFactory.openSession();
  39. try {
  40. IUserOperation userOperation = session
  41. .getMapper(IUserOperation.class);
  42. List<User> users = userOperation.selectUsersByName(userName);
  43. for (User user : users) {
  44. System.out.println(user.getId() + ":" + user.getUserName()
  45. + ":" + user.getUserAddress());
  46. }
  47. } finally {
  48. session.close();
  49. }
  50. }
  51. /**
  52. * 增加后要commit
  53. */
  54. public void addUser() {
  55. User user = new User();
  56. user.setUserAddress("place");
  57. user.setUserName("test_add");
  58. user.setUserAge(30);
  59. SqlSession session = sqlSessionFactory.openSession();
  60. try {
  61. IUserOperation userOperation = session
  62. .getMapper(IUserOperation.class);
  63. userOperation.addUser(user);
  64. session.commit();
  65. System.out.println("新增用户ID:" + user.getId());
  66. } finally {
  67. session.close();
  68. }
  69. }
  70. /**
  71. * 修改后要commit
  72. */
  73. public void updateUser() {
  74. SqlSession session = sqlSessionFactory.openSession();
  75. try {
  76. IUserOperation userOperation = session
  77. .getMapper(IUserOperation.class);
  78. User user = userOperation.selectUserByID(1);
  79. if (user != null) {
  80. user.setUserAddress("A new place");
  81. userOperation.updateUser(user);
  82. session.commit();
  83. }
  84. } finally {
  85. session.close();
  86. }
  87. }
  88. /**
  89. * 删除后要commit.
  90. *
  91. * @param id
  92. */
  93. public void deleteUser(int id) {
  94. SqlSession session = sqlSessionFactory.openSession();
  95. try {
  96. IUserOperation userOperation = session
  97. .getMapper(IUserOperation.class);
  98. userOperation.deleteUser(id);
  99. session.commit();
  100. } finally {
  101. session.close();
  102. }
  103. }
  104. public void getUserArticles(int userid) {
  105. SqlSession session = sqlSessionFactory.openSession();
  106. try {
  107. IArticleOperation articleOperation = session
  108. .getMapper(IArticleOperation.class);
  109. List<Article> articles = articleOperation.getUserArticles(userid);
  110. for (Article article : articles) {
  111. System.out.println(article.getTitle() + ":"
  112. + article.getContent() + "用户名:"
  113. + article.getUser().getUserName() + "用户地址:"
  114. + article.getUser().getUserAddress());
  115. }
  116. } finally {
  117. session.close();
  118. }
  119. }
  120. public void getBlogArticles(int blogid) {
  121. SqlSession session = sqlSessionFactory.openSession();
  122. try {
  123. IBlogOperation blogOperation = session
  124. .getMapper(IBlogOperation.class);
  125. Blog blog = blogOperation.getBlogByID(blogid);
  126. System.out.println(blog.getTitle() + ":");
  127. List<Article> articles = blog.getArticles();
  128. for (Article article : articles) {
  129. System.out.println(article.getTitle() + ":"
  130. + article.getContent() + "用户名:"
  131. + article.getUser().getUserName() + "用户地址:"
  132. + article.getUser().getUserAddress());
  133. /*System.out.println(article.getTitle() + ":"
  134. + article.getContent());*/
  135. }
  136. } finally {
  137. session.close();
  138. }
  139. }
  140. public static void main(String[] args) {
  141. try {
  142. Test test = new Test();
  143. // test.getUserByID(1);
  144. // test.getUserList("test1");
  145. // test.addUser();
  146. // test.updateUser();
  147. // test.deleteUser(6);
  148. //test.getUserArticles(1);
  149. test.getBlogArticles(1);
  150. } catch (Exception e) {
  151. System.out.println(e.getMessage());
  152. }
  153. }
  154. }

复制代码

Mybatis的“N+1查询问题”

示例:

复制代码

  1. <resultMap id=”blogResult” type=”Blog”>
  2. <association property="author" column="blog_author_id"
  3. javaType="Author" select=”selectAuthor” />
  4. </resultMap>
  5. <select id=”selectBlog” parameterType=”int” resultMap=”blogResult”>
  6. SELECT * FROM BLOG WHERE ID = #{id}
  7. </select>
  8. <select id=”selectAuthor” parameterType=”int” resultType="Author">
  9. SELECT * FROM AUTHOR WHERE ID = #{id}
  10. </select>

复制代码

有两个查询语句:一个来加载博客,另外一个来加载作者,而且博客的结果映射描述了“selectAuthor”语句应该被用来加载它的 author 属性。

其他所有的属性将会被自动加载,假设它们的列和属性名相匹配。

这种方式很简单,但是对于大型数据集合和列表将不会表现很好。问题就是我们熟知的“N+1 查询问题”。概括地讲,N+1 查询问题可以是这样引起的:

你执行了一个单独的 SQL 语句来获取结果列表(就是“+1”)。

对返回的每条记录,你执行了一个查询语句来为每个加载细节(就是“N”)。

这个问题会导致成百上千的 SQL 语句被执行。这通常不是期望的。

可以采用关联的嵌套结果来解决这个问题:

复制代码

  1. <resultMap id="blogResult" type="Blog">
  2. <id property=”id” column="blog_id" />
  3. <result property="title" column="blog_title" />
  4. <association property="author" column="blog_author_id"
  5. javaType="Author" resultMap=”authorResult” />
  6. </resultMap>
  7. <resultMap id="authorResult" type="Author">
  8. <id property="id" column="author_id" />
  9. <result property="username" column="author_username" />
  10. <result property="password" column="author_password" />
  11. <result property="email" column="author_email" />
  12. <result property="bio" column="author_bio" />
  13. </resultMap>

复制代码

resultMap 这是结果映射的 ID,可以映射关联的嵌套结果到一个合适的对象图中。这是一种替代方法来调用另外一个查询语句。

发表评论

表情:
评论列表 (有 0 条评论,273人围观)

还没有评论,来说两句吧...

相关阅读

    相关 MyBatis关联查询

      前言 我们进行数据库查询时往往需要的不止一张表的数据,需要将多张表的数据一起查询出来,大家学习过数据库的连接查询,那么在MyBatis中如何将有关系的多张表数据进行关联

    相关 Mybatis关联查询

    Mybatis关联查询 演示的数据表为: ![Center][] 部门和员工属于一对多关系。接下来演示的是根据员工编号查询员工信息并关联查询所在部门信息,查询所有部