Mybatis关联查询(嵌套查询)
上一篇文章介绍了基于Mybatis对数据库的增、删、改、查。这一篇介绍下关联查询(join query)。
三张表: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 ('', 'summer', '', 'shanghai');
INSERT INTO `user` VALUES ('', 'test1', '', 'suzhou');
INSERT INTO `user` VALUES ('', 'test1', '', 'some place');
INSERT INTO `user` VALUES ('', 'lu', '', 'some place');
INSERT INTO `user` VALUES ('', 'xiaoxun', '', '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 ('', '', 'test_title_1', 'test_content_1', '');
INSERT INTO `article` VALUES ('', '', 'test_title_2', 'test_content_2', '');
INSERT INTO `article` VALUES ('', '', 'test_title_3', 'test_content_3', '');
INSERT INTO `article` VALUES ('', '', 'test_title_4', 'test_content_4', '');
INSERT INTO `article` VALUES ('', '', 'test_title_5', 'test_content_5', ''); -- ----------------------------
-- 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 ('', 'xiaoxun_blog');
INSERT INTO `blog` VALUES ('', '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
Mybatis关联查询(嵌套查询)的更多相关文章
- Mybatis关联一对多映射不能查询出所有的数据的问题
在使用Mybatis进行一对多查询时,如果返回的是一个对象的话,可以发现将一对多的数据全都取出来了,但是这样的缺点是有很多值为null,我们更喜欢将返回值设为Map的形式,这样可以去除那些多余null ...
- 关于mysql中的数据查询—嵌套查询
嵌套查询 一个SELECT FROM WHERE语句称为一个查询块. 嵌套查询:将一个查询块嵌套在另一个查询块的WHERE子句或者HAVING短语的条件中的查询. 注:子查询的SELECT语句中不 ...
- SQL子查询/嵌套查询
sql子查询 嵌套SELECT语句 嵌套SELECT语句也叫子查询,一个 SELECT 语句的查询结果能够作为另一个语句的输入值.子查询不但能够出现在Where子句中,也能够出现在from子句中,作为 ...
- mongodb多个条件查询in,日期查询,嵌套查询,统计集合总数等常用实例
1. 多个条件查询in in db.inventory.find( { qty: { $in: [ 5, 15 ] } } ) 2. 日期查询 db.books.find({}) 查询时间大于6-,结 ...
- Mybatis之collection嵌套查询mapper文件写法
mapper.xml写法举例 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper ...
- mybatis两种嵌套查询方式
1,推荐用第一种 <select id="getTeacher2" resultMap="TeacherStudent"> select s.id ...
- 数据库SQL语言学习--上机练习2(连接查询 嵌套查询)
上机练习2 1. 启动SQL Server 2008中的 SQL Server Management Studio. 2. 针对下面三张基本表进行操 ...
- MyBatis关联查询 (association) 时遇到的某些问题/mybatis映射
先说下问题产生的背景: 最近在做一个用到MyBatis的项目,其中有个业务涉及到关联查询,我是将两个查询分开来写的,即嵌套查询,个人感觉这样更方便重用: 关联的查询使用到了动态sql,在执行查询时就出 ...
- MyBatis之Mapper XML 文件详解(四)-JDBC 类型和嵌套查询
支持的 JDBC 类型为了未来的参考,MyBatis 通过包含的 jdbcType 枚举型,支持下面的 JDBC 类型. BITFLOATCHARTIMESTAMPOTHERUNDEFINEDTINY ...
- mybatis的嵌套查询(嵌套查询nested select和嵌套结果nested results查询)区别
(转自:http://blog.csdn.net/canot/article/details/51485955) Mybatis表现关联关系比hibernate简单,没有分那么细致one-to-man ...
随机推荐
- Fiddler 抓包工具总结
阅读目录 1. Fiddler 抓包简介 1). 字段说明 2). Statistics 请求的性能数据分析 3). Inspectors 查看数据内容 4). AutoResponder 允许拦截制 ...
- UIDynamic(简单介绍)
一.简单介绍 1.什么是UIDynamic UIDynamic是从iOS 7开始引入的一种新技术,隶属于UIKit框架 可以认为是一种物理引擎,能模拟和仿真现实生活中的物理现象 如:重力.弹性碰撞等现 ...
- wpf converter converterparameter 绑定多参数
1. converterparameter不是依赖属性,所以不能用binding. 2. 可以把converter 的接口 IValueConverter改为 IMultiValueConverter ...
- 戴尔OMSA 使用指南
戴尔的OMSA我们已经安装完成,但是没有web页面.因此我们目前想要看到服务器的相关硬件信息就需要使用命令行的方式获取了.那么,这里就介绍如何使用命令获取服务器硬件信息. 下面是我监控一些硬件信息的命 ...
- [Unity3D]添加音效说明
添加音效组件并添加音乐资源 其中Pitch用来提高和降低音调的,比如可以和赛车游戏的轮胎绑定,当轮胎越快,则音调越高 2D/3D音效:2D音效和摄影家的距离无关,可以看做是一个背景音乐:而3D音效则是 ...
- 关于linux asp.net MVC网站中 httpHandlers配置无效的处理方法
近期有Jexus用户反映,在Linux ASP.NET MVC网站的Web.config中添加 httpHandlers 配置用于处理自定义类型,但是在运行中并没有产生预期的效果,服务器返回了404( ...
- Twemproxy 缓存代理服务器
Twemproxy 缓存代理服务器 Twemproxy 概述 Twemproxy(又称为nutcracker)是一个轻量级的Redis和Memcached代理,主要用来减少对后端缓存服务器的连接数.T ...
- CSS 和 JS 动画哪个更快
基于Javascript的动画暗中同CSS过渡效果一样,甚至更加快,这怎么可能呢?而Adobe和Google持续发布的富媒体移动网站的性能可媲美本地应用,这又怎么可能呢? 本文逐一遍览了基于Javas ...
- php 301 重定向 转自http://www.icoa.cn/a/475.html
内容简介 有时候我们的有多个域名指向同一个网站,或者我们更换了网站的网址,那么怎么样将原来网站的流量导入到新网址中呢,那么我们可以用301重定向的方式,而且这种方式是对搜索引擎比较友好的方式.如果首页 ...
- 第3月第11天 vs2005调试 ace编译
1.vs2005调试 http://blog.csdn.net/u010797208/article/details/40452797 2.macbook ace编译 小坑: 源代码clockid_t ...