Mybatis多表查询之一对一查询的多种实现-XML配置
Mybatis 中对于多表查询提供了非常强大的实现方式,主要是通过resultMap的结果映射对于多表查询后的返回值进行封装,让我们来看一下官网上对于resultMap的解释:resultMap 元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets 数据提取代码中解放出来,并在一些情形下允许你进行一些 JDBC 不支持的操作。实际上,在为一些比如连接的复杂语句编写映射代码的时候,一份 resultMap 能够代替实现同等功能的长达数千行的代码。ResultMap 的设计思想是,对于简单的语句根本不需要配置显式的结果映射,而对于复杂一点的语句只需要描述它们的关系就行了。通过描述对象之间的关系将查询后的结果映射到我们定义的实体类中。
首先介绍一下本例中的实体类以及其映射关系,Demo中存在User类以及Account类,其关系为一个用户对应零个、一个或者多个账户,账户中为了简单单单保存用户的账户余额以及所属用户的ID。我们实现的查询的目标为:每次查询一个账户的时候同时将其所属的用户信息也展示出来。为了更好的帮助理解,我们将展示一种非mybatis方式以及两种mybatis方式的实现来实现。User类以及Accoun类t的内容如下:
import java.io.Serializable;
public class Account implements Serializable{
private Integer id;
private Integer uid;
private Double money;
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", uid=" + uid +
", money=" + money +
'}';
}
}
import java.io.Serializable;
import java.util.Date; public class User implements Serializable{
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address; public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public String getUsername() {
return username;
} public void setUsername(String username) {
this.username = username;
} public Date getBirthday() {
return birthday;
} public void setBirthday(Date birthday) {
this.birthday = birthday;
} public String getSex() {
return sex;
} public void setSex(String sex) {
this.sex = sex;
} public String getAddress() {
return address;
} public void setAddress(String address) {
this.address = address;
} @Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", birthday=" + birthday +
", sex='" + sex + '\'' +
", address='" + address + '\'' +
'}';
}
}
数据库的建表语句如下:
DROP TABLE IF EXISTS user; CREATE TABLE user (
id INT(11) NOT NULL auto_increment,
username VARCHAR(32) NOT NULL COMMENT '用户名称',
birthday datetime default NULL COMMENT '生日',
sex char(1) default NULL COMMENT '性别',
address varchar(256) default NULL COMMENT '地址',
PRIMARY KEY (id)
)ENGINE=InnoDB default CHARSET=utf8
INSERT INTO `user` VALUES ('', '老王', '2018-02-27 17:47:08', '男', '石家庄');
INSERT INTO `user` VALUES ('', '老李', '2018-02-27 17:47:08', '男', '石家庄');
INSERT INTO `user` VALUES ('', '老郭', '2018-02-27 17:47:08', '男', '石家庄'); DROP TABLE IF EXISTS account;
CREATE TABLE account(
ID int(11) NOT NULL COMMENT '编号',
UID INT(11) DEFAULT NULL COMMENT '用户编号',
MONEY DOUBLE DEFAULT NULL COMMENT '金额',
PRIMARY KEY (ID),
KEY FK_Reference_8 (UID),
CONSTRAINT FK_Reference_8 FOREIGN KEY (UID) REFERENCES user (id)
)ENGINE=INNODB DEFAULT CHARSET=utf8 INSERT INTO accountc (ID,UID,MONEY) VALUES (1,46,1000),(2,45,1000),(3,46,2000);
搭建项目的过程就不展示了,主要的核心实体类和对应的数据库表如上,接下来我们展示我们所要展示的三种方式实现一对一的联表查询。
1.非mybatis的高级结果映射方式实现联表查询。
这种方式的原理为通过创建一个新的类AccountUser类继承Account类并在AccountUser类中添加我们想要查询的User的信息,并且在账户查询的Dao.xml文件中配置相应的sql语句即可实现。假如我们查询Account的信息的时候同时想要查询用户的名称以及地址,那就在AccountUser的类中声明用户的名称以及地址。这种实现方式只是作为一种拓展的实现方式,在实际使用过程中并不推荐使用。
(1)声明AccountUser类
public class AccountUser extends Account {
private String username;
private String address;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return super.toString() + " "+"AccountUser{" +
"username='" + username + '\'' +
", address='" + address + '\'' +
'}';
}
}
需要注意的是该类继承了Account类,声明了我们需要的User类中的用户名称以及地址,对AccountUser类的toString()方法进行了改造,添加了super.toString(),方便我们打印的时候可以打印出从父类中继承的属性的属性值。
(2)在AccountDao类中声明查询账户信息的方法
/**
* 查找所有账户同时包含用户的姓名和地址
* @return
*/
List<AccountUser> findAllAccountUser();
(3)在AccountDao.xml中配置findAllAccountUser方法的实现
<select id="findAllAccountUser" resultType="com.example.domain.AccountUser">
SELECT a.*,u.username,u.address FROM USER u,account a WHERE a.UID= u.id;
</select>
(4)测试该方法
@Test
public void findAllAccounUsertTest(){
List<AccountUser> accountList = accountDao.findAllAccountUser();
for (AccountUser account:accountList){
System.out.println(account);
}
}
测试结果:
2.通过Mybatis中的高级结果映射的resultMap的关联属性(association)来实现多表的一对一查询。
关联属性主要用来处理“有一个”类型的关系,关联的关键之处是我们需要告诉 MyBatis 如何加载关联。在MyBatis 中有两种不同的方式加载关联:一是嵌套 Select 查询:通过执行另外一个 SQL 映射语句来加载期望的复杂类型。二是嵌套结果映射:使用嵌套的结果映射来处理连接结果的重复子集。通过这两种不同的方式衍生出两种不同的方式去实现多表的一对一查询。
1.关联的嵌套SELECT查询
(1)因为我们要实现的是在查询账户的时候期望可以得到账户所属用户的某些信息,所以我们需要在Account类中声明User对象,用来将查询到的结果进行封装。如下
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
(2)AccountDao类中添加查询的方法的声明。
/**
* 查找所有账户同时包含用户的所有信息
* @return
*/
List<Account> findAll();
(3)在AccountDao.xml中配置findAll方法的的结果映射。首先声明结果映射关系resultMap,resultMap的id为该结果映射的唯一标识,type为结果类的完全限定名,resultMap中的属性说明:id 和 result 元素都将一个列的值映射到一个简单数据类型(String, int, double, Date 等)的属性或字段。这两者之间的唯一不同是,id 元素表示的结果将是对象的标识属性,这会在比较对象实例时用到。 这样可以提高整体的性能,尤其是进行缓存和嵌套结果映射(也就是连接映射)的时候。id和result中的属性说明:property
映射到列结果的字段或属性,其实就是实体类中属性的名称。column是指数据库中的列名,对应实体类的属性。在下面的<id property="id" column="aid"/>中的column属性的值aid没有完全匹配上数据中的id,是因为在查询语句中对account中的id字段设置了别名aid。association的属性的 property为user对应实体类中声明的user对象,其类型使用javaType属性指定为User类,column为数据表的列名,并作为参数传递给此 select 语句。select属性用于加载复杂类型属性的映射语句的 ID,它会从 column 属性中指定的列检索数据。
<resultMap id="accountUserMap" type="com.example.domain.Account">
<id property="id" column="aid"/>
<result property="uid" column="uid"/>
<result property="money" column="money"/>
<!--关联的嵌套的select查询-->
<association property="user" javaType="com.example.domain.User" column="uid" select="selectUser"/>
</resultMap>
(4)在AccountDao.xml中配置结果映射中的<association property="user" javaType="com.example.domain.User" column="uid" select="selectUser"/>的select="selectUser"的实现以及findAll方法的实现,
<select id="selectUser" resultType="user">
SELECT * FROM USER WHERE ID = #{id};
</select>
<select id="findAll" resultMap="accountUserMap">
SELECT u.*,a.id AS aid,a.uid,a.money FROM USER u,account a WHERE a.UID= u.id;
</select>
这里我们有两个 select 查询语句:一个用来加载账户信息(Account),另外一个用来加载用户信息(User),而且accountUserMap的结果映射描述了应该使用 selectUser 语句加载它的 user属性,其它的列名和属性名相匹配的属性将会被自动加载。
(5)查询测试
@Test
public void findAllTest(){
List<User> userList = userDao.findAll();
for (User user: userList){
System.out.println(user);
}
}
测试结果:
2.关联的嵌套结果映射实现1。
(1)(2)步骤是上一方法是相同的。
(3)主要是修改了上一种方式中第三步中的resultMap中的association关联属性,将其替换为:<association property="user" javaType="com.example.domain.User" column="uid" resultMap="userMap"/>,在association 中添加了resultMap="userMap"属性,userMap为结果映射的 ID,可以将此关联的嵌套结果集映射到一个合适的对象中,也就是将关联属性user的结果映射到映射ID为userMap的resultMap中。userMap的声明如下:
<resultMap id="userMap" type="com.example.domain.User">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="birthday" column="birthday" jdbcType="DATE"/>
<result property="sex" column="sex"/>
<result property="address" column="address"/>
</resultMap>
(4)AccountDao.xml的findAll方法的映射则只需要findAll方法,不再需要上一个方式中的selectUser映射的方法
<select id="findAll" resultMap="accountUserMap">
SELECT u.*,a.id AS aid,a.uid,a.money FROM USER u,account a WHERE a.UID= u.id;
</select>
(5)(6)查询代码以及测试结果不再贴出
3.关联的嵌套结果映射实现2。
第二种实现方式中使用了外部的结果映射元素来映射关联。这使得 User的结果映射可以被重用。 然而,如果我们不需要重用它(在上个例子中他是userMap),或者你更喜欢将你所有的结果映射放在一个具有描述性的结果映射元素中。 你可以直接将结果映射作为子元素嵌套在内。
(1)(2)步骤是上一方法是相同的。
(3)仍然是修改了上一种方式中第三步中的resultMap结果映射中的association关联属性,将其替换如下:
<!--关联的嵌套的结果映射2-->
<association property="user" javaType="com.example.domain.User">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="birthday" column="birthday" jdbcType="DATE"/>
<result property="sex" column="sex"/>
<result property="address" column="address"/>
</association>
这样实现与第二种实现大同小异,只是将关联对象的属性配置直接在association中进行了配置。
(4)AccountDao.xml的findAll方法的映射的findAll方法
<select id="findAll" resultMap="accountUserMap">
SELECT u.*,a.id AS aid,a.uid,a.money FROM USER u,account a WHERE a.UID= u.id;
</select>
(5)(6)查询代码以及测试结果不再贴出
总结:通过上述例子可以初步窥探了Mybatis中多表联查(一对一)的使用方式,主要是通过resultMap的高级结果映射来实现的,在本例中最关键的属性是resultMap的关联属性association,association也是我们告诉Mybatis对象之间的关系的桥梁,同时也介绍了resultMap的属性的说明,通过解释其属性再加上Demo可以更好的理解结果映射的含义以及使用,这只是最简单的一种使用方式,以后会详细介绍一对多、多对多、多对一等复杂情况在Mybatis中的如何查询映射。
参考网址:mybatis中文官网 http://www.mybatis.org/mybatis-3/zh/sqlmap-xml.html
Mybatis多表查询之一对一查询的多种实现-XML配置的更多相关文章
- MyBatis 高级查询之一对一查询(九)
高级查询之一对一查询 查询条件:根据游戏角色ID,查询账号信息 我们在之前创建的映射器接口 GameMapper.java 中添加接口方法,如下: /** * 根据角色ID查询账号信息 * @para ...
- Mybatis高级查询之一对一查询的四种方法
目录 1. 一对一查询 1.1 一对一嵌套结果查询 1.2 使用resultMap配置一对一映射 1.3 使用resultMap的association标签配置一对一映射 1.4 associatio ...
- mybatis关联查询之一对一查询
一对一也就是 A 表的一条记录对应 B 表的一条记录,下面的测试数据中,从employee 表来看,一个员工对应一个部门,是一对一关系,如果从部门角度来看,则是一对多的关系,一个部门对应多个员工,本节 ...
- mybatis多表连接在一起查询
实体类 和 xml (这里用了几个典型的数据类型,都是其他表的字段) private String marriage;//图片 remarks private Date createtime;//公告 ...
- Mybatis关联查询之一对多和多对一XML配置详解
平时在开发过程中dao.bean和XML文件都是自动生成的,很少写XML的配置关系,今天记录一下mybatis的关联查询中的多对一和一对多的情况. 首先是有两张表(学生表Student和老师Teach ...
- Django【第7篇】:Django之ORM跨表操作(聚合查询,分组查询,F和Q查询等)
django之跨表查询及添加记录 一:创建表 书籍模型: 书籍有书名和出版日期,一本书可能会有多个作者,一个作者也可以写多本书,所以作者和书籍的关系就是多对多的关联关系(many-to-many); ...
- Mybatis多表操作
一:引言 在学习完前面的mybatis基本语法后,大家都有个认知,这个Mybatis太强大了,比之前使用JDBC写方便多了,但是你们当初在使用原生JDBC写SQL查询的时候有没有遇到过多表查询呢?肯定 ...
- Mybatis多表查询(一对一、一对多、多对多)
Mybatis的多表级联查询 . 一对一可以通过<association>实现,一对多和多对多通过<collection>实现. <discriminator> 元 ...
- mybatis进阶--一对一查询
所谓的一对一查询,就是说我们在查询一个表的数据的时候,需要关联查询其他表的数据. 需求 首先说一个使用一对一查询的小需求吧:假设我们在查询某一个订单的信息的时候,需要关联查询出创建这个订单对应的用户信 ...
随机推荐
- UVA514 铁轨 Rails:题解
题目链接:https://www.luogu.org/problemnew/show/UVA514 分析: 入站序列是1-n,入站后判断如果等于出站序列的当前值,则直接出站.否则就在栈里待着不动.模拟 ...
- 个人永久性免费-Excel催化剂功能第34波-提取中国身份证信息、农历日期转换相关功能
这两天又被刷朋友圈,又来了一个自主研发红芯浏览器,国产啊国产,这是谁的梦.就算国产了,自主了,无底线的夸大吹嘘无道德,企业如是,国家如是,大清已亡!再牛B的技术落在天天删敏感信息.无法治.无安全感可言 ...
- Spring_AOP基于AspectJ的注解开发&JDBC的模板使用&事务管理(学习笔记3)
一:AOP基于AspectJ的注解开发 1,简单的实例: 1)引入相应的jar包 2)在配置文件里引入相关约束 <beans xmlns="http://www.springfra ...
- Yarn工作机制
概述 (0)Mr 程序提交到客户端所在的节点. (1)Yarnrunner 向 Resourcemanager 申请一个 Application. (2)rm将该应用程序的资源路径和Applicati ...
- sql注入篇1
一.前言 学习了感觉很久的渗透,总结一下sql注入,系统整理一下sql注入思路. 二.关于sql注入 所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到 ...
- Gin框架 - 自定义错误处理
目录 概述 错误处理 自定义错误处理 panic 和 recover 推荐阅读 概述 很多读者在后台向我要 Gin 框架实战系列的 Demo 源码,在这里再说明一下,源码我都更新到 GitHub 上, ...
- 阿里云服务器连接以及centos 搭建 web java环境(linux java部署 tomcat部署)
版权声明:本文为博主原创文章,未经博主允许不得转载. 最近弄了个试用阿里云服务器倒腾了半天终于部署好,分享一下. 1.登入阿里云打开你申请的是云服务器的实例: 点击重置密码---重置密码后重启服务器才 ...
- linux初学者-常用基本命令篇
linux系统中有着许许多多的命令,并且软件也有可能自带命令,要想全部了解这些命令是很困难的,但是有一些基本命令是在平时的学习工作中应用的很广泛的.以下简要介绍几种linux系统中的常用命令. 1.m ...
- 勘误:EOS资源抵押退还
关键字:勘误,delegatebw,undelegatebw,listbw,资源管理,抵押,解抵押,返还资源 EOS中,资源抵押与解抵押是通过一对命令完成的:delegatebw,undelegate ...
- GitLab与Git的结合
作为一名刚入职的大数据初级开发工程师,来到公司后发现代码是部署在GItLab上,之前一直认为代码可以放在码云.github上面,然后就很迷惑就对GitLab进行了了解,将git 和gitlab结合起来 ...