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进阶--一对一查询
所谓的一对一查询,就是说我们在查询一个表的数据的时候,需要关联查询其他表的数据. 需求 首先说一个使用一对一查询的小需求吧:假设我们在查询某一个订单的信息的时候,需要关联查询出创建这个订单对应的用户信 ...
随机推荐
- Docker+Maven+Jenkins在Devops中完整应用
过去与现在 很早之前,当我们需要一个部署环境的时候,我们可能指的是一台PowerEdge R710 2U服务器,走一系列冗长的申请流程,然后上架到机房.调试网络.安装系统.调试环境.最终部署应用,就这 ...
- redis分布式锁的问题和解决
分布式锁 在分布式环境中,为了保证业务数据的正常访问,防止出现重复请求的问题,会使用分布式锁来阻拦后续请求.具体伪代码如下: public void doSomething(String userId ...
- C#3.0新增功能06 对象和集合初始值设定项
连载目录 [已更新最新开发文章,点击查看详细] 使用 C# 可以在单条语句中实例化对象或集合并执行成员分配. 对象初始值设定项 使用对象初始值设定项,你可以在创建对象时向对象的任何可访问字段或属 ...
- 使用canvas来完成线性渐变和径向渐变的功能
fillStyle的第二种使用情况就是渐变色的填充.渐变色就分为线性渐变色和径向渐变色. 线性渐变:大致分为两步 这里又会使用到canvas的两个新的函数. 第一步 : 使用一个新的函数cre ...
- IIS身份验证和文件操作权限(一、身份验证配置)
最近有一个项目服务器需要升级,主要是Web项目.因为以前是只写代码,不管发布.所以在环境构筑方面就出现自己的知识盲点.盲点一:IIS的身份验证的作用盲点二:IIS的身份验证和文件操作权限的关系(重点) ...
- context创建过程解析(一)之deployDescriptors
总结:主要是创建Context对象,并且将默认context配置,host级别配置,context配置的值设置进去,设置docBase,如果是war包就解压到webapp的目录中,重新设置docBas ...
- PageHelper分页实战(SSM整合)
步骤一:引入SSM相关的jar包,包列表如下: 步骤二:创建或修改配置文件,配置文件清单如下: applicationContext.xml <?xml version="1.0&qu ...
- jquery插件——仿新浪微博限制输入字数的textarea
内容链接地址:http://www.cnblogs.com/jone-chen/p/5213851.html: <!DOCTYPE html> <html> <head& ...
- Mybatis整合Spring 使用
1.继承通用的Mapper<T>,必须指定泛型<T> 例如下面的例子: public interface UserInfoMapper extends Mapper<Us ...
- solr 新建core
D:\tomcat\webapps\solr\solr_home 在该路径下创建一个新的core,所需文件和层级如下 test_core |-- conf |-- schema.xml |-- sol ...