Mybatis關聯查詢(嵌套查詢)

三張表:user article blog

表的存儲sql文件:

複製代碼

/*
Navicat MySQL Data Transfer

Source Server         : localhost
Source Server Version : 50620
Source Host           : localhost:3306
Source Database       : mybatis

Target Server Type    : MYSQL
Target Server Version : 50620
File Encoding         : 65001

Date: 2014-10-19 18:27:31
*/

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for `user`
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `userName` varchar(50) DEFAULT NULL,
  `userAge` int(11) DEFAULT NULL,
  `userAddress` varchar(200) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', 'summer', '30', 'shanghai');
INSERT INTO `user` VALUES ('2', 'test1', '22', 'suzhou');
INSERT INTO `user` VALUES ('3', 'test1', '29', 'some place');
INSERT INTO `user` VALUES ('4', 'lu', '28', 'some place');
INSERT INTO `user` VALUES ('5', 'xiaoxun', '27', 'nanjing');

-- ----------------------------
-- Table structure for `article`
-- ----------------------------
DROP TABLE IF EXISTS `article`;
CREATE TABLE `article` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `userid` int(11) NOT NULL,
  `title` varchar(100) DEFAULT NULL,
  `content` text,
  `blogid` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of article
-- ----------------------------
INSERT INTO `article` VALUES ('1', '1', 'test_title_1', 'test_content_1', '1');
INSERT INTO `article` VALUES ('2', '1', 'test_title_2', 'test_content_2', '1');
INSERT INTO `article` VALUES ('3', '1', 'test_title_3', 'test_content_3', '2');
INSERT INTO `article` VALUES ('4', '1', 'test_title_4', 'test_content_4', '2');
INSERT INTO `article` VALUES ('5', '2', 'test_title_5', 'test_content_5', '2');

-- ----------------------------
-- Table structure for `blog`
-- ----------------------------
DROP TABLE IF EXISTS `blog`;
CREATE TABLE `blog` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(200) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of blog
-- ----------------------------
INSERT INTO `blog` VALUES ('1', 'xiaoxun_blog');
INSERT INTO `blog` VALUES ('2', 'zhang_blog');

複製代碼

配置文件Configuration.xml

複製代碼

複製代碼
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- mybatis別名定義 -->
    <typeAliases> 
        <typeAlias alias="User" type="com.mybatis.test.User"/> 
        <typeAlias alias="Article" type="com.mybatis.test.Article"/> 
        <typeAlias alias="Blog" type="com.mybatis.test.Blog"/>
    </typeAliases> 

    <environments default="development">
        <environment id="development">
        <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
            <property name="driver" value="com.mysql.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis" />
            <property name="username" value="root"/>
            <property name="password" value="admin"/>
            </dataSource>
        </environment>
    </environments>
    
    <!-- mybatis的mapper文件,每個xml配置文件對應一個接口 -->
    <mappers>
        <mapper resource="com/mybatis/test/User.xml"/>
        <mapper resource="com/mybatis/test/Article.xml"/>
        <mapper resource="com/mybatis/test/Blog.xml"/>
    </mappers>
</configuration>

複製代碼

User類的定義和User.xml的配置見上一文章。

Article類定義:

複製代碼

package com.mybatis.test;

public class Article {

    private int id;
    private User user;
    private String title;
    private String content;
    
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    
    public User getUser() {
        return user;
    }
    public void setUser(User user) {
        this.user = user;
    }
    
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
    
}

複製代碼

Article類中有一個User類。

Article.xml的配置:

複製代碼

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.mybatis.test.IArticleOperation">

    <resultMap type="User" id="userResultMap">
        <!-- 屬性名和數據庫列名映射 -->
        <id property="id" column="user_id"  />
        <result property="userName" column="user_userName"  />
        <result property="userAge" column="user_userAge"  />
        <result property="userAddress" column="user_userAddress"  />
    </resultMap>
    
    <!-- User join Article進行聯合查詢  (一對一)-->    
    <resultMap id="articleResultMap" type="Article">
        <id property="id" column="article_id" />
        <result property="title" column="article_title" />
        <result property="content" column="article_content" />
        <!-- 將article的user屬性映射到userResultMap -->
        <association property="user" javaType="User" resultMap="userResultMap"/>  
    </resultMap>
    
    <!-- 使用別名來映射匹配 -->
    <select id="getUserArticles" parameterType="int" resultMap="articleResultMap">
       select user.id user_id,user.userName user_userName,user.userAddress user_userAddress,
       article.id article_id,article.title article_title,article.content article_content 
       from user,article 
       where user.id=article.userid and user.id=#{id}
    </select>
    
    <!-- 另一種聯合查詢  (一對一)的實現,但是這種方式有“N+1”的問題 -->
   <!--  <resultMap id="articleResultMap" type="Article">
        <id property="id" column="article_id" />
        <result property="title" column="article_title" />
        <result property="content" column="article_content" />
        <association property="user" javaType="User" column="userid" select="selectUser"/>  
    </resultMap>
    
    <select id="selectUser" parameterType="int" resultType="User">
        select * from user where id = #{id}
    </select> -->
    
</mapper>

複製代碼

Blog類定義:

複製代碼

package com.mybatis.test;

import java.util.List;

public class Blog {

    private int id;
    private String title;
    private List<Article> articles;
    
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    
    public List<Article> getArticles() {
        return articles;
    }
    public void setArticles(List<Article> articles) {
        this.articles = articles;
    }
    
}

複製代碼

Blog類中有一個List<Article>。

Blog.xml配置:

複製代碼

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.mybatis.test.IBlogOperation">

    <resultMap id="userResultMap" type="User">
        <id property="id" column="user_id"  />
        <result property="userName" column="user_userName"  />
        <result property="userAge" column="user_userAge"  />
        <result property="userAddress" column="user_userAddress"  />
    </resultMap>
    
    <resultMap id="articleResultMap" type="Article">
        <id property="id" column="article_id" />
        <result property="title" column="article_title" />
        <result property="content" column="article_content" />
        <association property="user" javaType="User" resultMap="userResultMap"/>  
    </resultMap>
    
    <resultMap id="blogResultMap" type="Blog">
        <id property="id" column="blog_id" />
        <result property="title" column="blog_title" />
        <!-- 將article list屬性映射到collection -->
        <collection property="articles" ofType="Article" resultMap="articleResultMap"/>
    </resultMap>
    
    <!-- select語句 -->
    <select id="getBlogByID" parameterType="int" resultMap="blogResultMap">
       select user.id user_id,user.userName user_userName,user.userAddress user_userAddress,
       article.id article_id,article.title article_title,article.content article_content, 
       blog.id blog_id, blog.title blog_title
       from user,article,blog 
       where user.id=article.userid and blog.id=article.blogid and blog.id=#{id}
    </select>
    
</mapper>

複製代碼

IArticleOperation定義:

複製代碼

package com.mybatis.test;

import java.util.List;

public interface IArticleOperation {

    public List<Article> getUserArticles(int userID);
}

複製代碼

IBlogOperation定義:

複製代碼

package com.mybatis.test;

public interface IBlogOperation {
    
    Blog getBlogByID(int id);
    
}

複製代碼

Test類:

複製代碼

package com.mybatis.test;

import java.io.Reader;
import java.util.List;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class Test {

    private static SqlSessionFactory sqlSessionFactory;
    private static Reader reader;

    static {
        try {
            //通過配置文件初始化sqlSessionFactory
            reader = Resources.getResourceAsReader("Configuration.xml");
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static SqlSessionFactory getSession() {
        return sqlSessionFactory;
    }

    public void getUserByID(int userID) {
        SqlSession session = sqlSessionFactory.openSession();
        try {
            IUserOperation userOperation = session
                    .getMapper(IUserOperation.class);
            User user = userOperation.selectUserByID(userID);
            if (user != null) {
                System.out.println(user.getId() + ":" + user.getUserName()
                        + ":" + user.getUserAddress());
            }

        } finally {
            session.close();
        }
    }

    public void getUserList(String userName) {
        SqlSession session = sqlSessionFactory.openSession();
        try {
            IUserOperation userOperation = session
                    .getMapper(IUserOperation.class);
            List<User> users = userOperation.selectUsersByName(userName);
            for (User user : users) {
                System.out.println(user.getId() + ":" + user.getUserName()
                        + ":" + user.getUserAddress());
            }

        } finally {
            session.close();
        }
    }

    /**
     * 增加後要commit
     */
    public void addUser() {
        User user = new User();
        user.setUserAddress("place");
        user.setUserName("test_add");
        user.setUserAge(30);
        SqlSession session = sqlSessionFactory.openSession();
        try {
            IUserOperation userOperation = session
                    .getMapper(IUserOperation.class);
            userOperation.addUser(user);
            session.commit();
            System.out.println("新增用戶ID:" + user.getId());
        } finally {
            session.close();
        }
    }

    /**
     * 修改後要commit
     */
    public void updateUser() {
        SqlSession session = sqlSessionFactory.openSession();
        try {
            IUserOperation userOperation = session
                    .getMapper(IUserOperation.class);
            User user = userOperation.selectUserByID(1);
            if (user != null) {
                user.setUserAddress("A new place");
                userOperation.updateUser(user);
                session.commit();
            }
        } finally {
            session.close();
        }
    }

    /**
     * 刪除後要commit.
     * 
     * @param id
     */
    public void deleteUser(int id) {
        SqlSession session = sqlSessionFactory.openSession();
        try {
            IUserOperation userOperation = session
                    .getMapper(IUserOperation.class);
            userOperation.deleteUser(id);
            session.commit();
        } finally {
            session.close();
        }
    }

    public void getUserArticles(int userid) {
        SqlSession session = sqlSessionFactory.openSession();
        try {
            IArticleOperation articleOperation = session
                    .getMapper(IArticleOperation.class);
            List<Article> articles = articleOperation.getUserArticles(userid);
            for (Article article : articles) {
                System.out.println(article.getTitle() + ":"
                        + article.getContent() + "用戶名:"
                        + article.getUser().getUserName() + "用戶地址:"
                        + article.getUser().getUserAddress());
            }
        } finally {
            session.close();
        }
    }

    public void getBlogArticles(int blogid) {
        SqlSession session = sqlSessionFactory.openSession();
        try {
            IBlogOperation blogOperation = session
                    .getMapper(IBlogOperation.class);
            Blog blog = blogOperation.getBlogByID(blogid);
            System.out.println(blog.getTitle() + ":");
            List<Article> articles = blog.getArticles();
            for (Article article : articles) {
                System.out.println(article.getTitle() + ":"
                        + article.getContent() + "用戶名:"
                        + article.getUser().getUserName() + "用戶地址:"
                        + article.getUser().getUserAddress());
                /*System.out.println(article.getTitle() + ":"
                        + article.getContent());*/
            }
        } finally {
            session.close();
        }
    }

    public static void main(String[] args) {
        try {
            Test test = new Test();
            // test.getUserByID(1);
            // test.getUserList("test1");
            // test.addUser();
            // test.updateUser();
            // test.deleteUser(6);

            //test.getUserArticles(1);

            test.getBlogArticles(1);

        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

}

複製代碼

Mybatis的“N+1查詢問題”

複製代碼

<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 查詢問題可以是這樣引起的:

你執行了一個單獨的 SQL 語句來獲取結果列表(就是“+1”)。

對返回的每條記錄,你執行了一個查詢語句來爲每個加載細節(就是“N”)。

這個問題會導致成百上千的 SQL 語句被執行。這通常不是期望的。

可以採用關聯的嵌套結果來解決這個問題:

複製代碼

 <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>

複製代碼

resultMap 這是結果映射的 ID,可以映射關聯的嵌套結果到一個合適的對象圖中。這是一種替代方法來調用另外一個查詢語句。

 

代碼下載:http://download.csdn.net/detail/luxiaoxun/8056559

 

參考:

http://www.mybatis.org/mybatis-3/zh/sqlmap-xml.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章