当前位置: 首页>编程语言>正文

【MyBatis】Mybatis 多表查询


文章目录

  • ​​Mybatis 多表查询​​
  • ​​一、表之间的关系​​
  • ​​二、准备工作​​
  • ​​2.1 创建account表​​
  • ​​2.2 创建Account、User实体类​​
  • ​​2.3 Dao层、映射文件配置​​
  • ​​2.4 主配置文件SqlMapConfig.xml​​
  • ​​2.5 测试类配置​​
  • ​​三、一对一查询(多对一)​​
  • ​​3.1 编写sql语句​​
  • ​​方式一:查询信息实体类​​
  • ​​3.2.1 创建 AccountUser 类​​
  • ​​3.2.2 IAccountDao​​
  • ​​3.2.3 IAccountDao.xml 文件中的查询配置信息​​
  • ​​3.2.4 AccountTest 测试类​​
  • ​​方式二:添加主从关系对象属性​​
  • ​​3.3.1 修改 Account 类​​
  • ​​3.3.2 修改 AccountDao 接口中的方法​​
  • ​​3.3.3 重新定义 IAccountDao.xml 文件​​
  • ​​3.3.4 测试​​
  • ​​四、一对多查询​​
  • ​​4.1 编写sql语句​​
  • ​​4.2 修改 User 类​​
  • ​​4.3 IUserDao​​
  • ​​4.4 IUserDao.xml配置​​
  • ​​4.5 测试​​
  • ​​五、多对多查询​​
  • ​​5.1 户与角色的关系模型​​
  • ​​5.2 业务要求及实现 SQL​​
  • ​​5.2.1 编写 SQL 语句​​
  • ​​5.2.2 编写角色实体类​​
  • ​​5.2.3 IRoleDao​​
  • ​​5.2.4 IRoleDao.xml​​
  • ​​5.2.5 测试​​

Mybatis 多表查询

一、表之间的关系

常见的表之间的对应关系:

  • 一对多
  • 多对一
  • 一对一
  • 多对多

举例:

  • 用户和订单就是一对多
  • 订单和用户就是多对一
  • 一个用户可以下多个订单
  • 多个订单属于同一个用
  • 人和身份证号就是一对一
  • 一个人只能有一个身份证号
  • 一个身份证号只能属于一个人
  • 老师和学生之间就是多对多
  • 一个学生可以被多个老师教过
  • 一个老师可以交多个学生
  • 特例:
  • 如果拿出每一个订单,他都只能属于一个用户;所以 MyBatis 就把 多对一 看成了 一对一。

​​返回顶部​​


二、准备工作

【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_学习笔记,第1张

2.1 创建account表

mysql> use ssm;
Database changed
mysql> 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 `account`(`ID`,`UID`,`MONEY`) values (1,46,1000),(2,45,1000),(3,46,2000);
Query OK, 0 rows affected (0.01 sec)
Query OK, 0 rows affected (0.16 sec)
Query OK, 3 rows affected (0.01 sec)
Records: 3 Duplicates: 0 Warnings: 0

mysql> select * from account;
+----+-----+-------+
| ID | UID | MONEY |
+----+-----+-------+
| 1 | 46 | 1000 |
| 2 | 45 | 1000 |
| 3 | 46 | 2000 |
+----+-----+-------+
3 rows in set (0.04 sec)

​​返回顶部​​


2.2 创建Account、User实体类

  • 注意字段的对应
  • 【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_sql_02,第2张

  • ​​返回顶部​​

2.3 Dao层、映射文件配置

  • 配置最基本的 findAll() 查询接口、sql
  • 【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_sql_03,第3张

  • ​​返回顶部​​

2.4 主配置文件SqlMapConfig.xml

  • 配置主配置的映射文件路径,也可以使用package标签使用包路径的扫描
  • 【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_学习笔记_04,第4张

  • ​​返回顶部​​

2.5 测试类配置

import com.zyx.core.dao.IAccountDao;
import com.zyx.core.dao.IUserDao;
import com.zyx.core.domain.Account;
import com.zyx.core.domain.AccountUser;
import com.zyx.core.domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

public class AccountTest {

InputStream in = null;
SqlSession sqlSession;
IAccountDao iAccountDao;

/**
* 初始化方法
*/
@Before // 用于在测试方法执行之前执行
public void init() {
try {
// 1.读取主配置文件
in = Resources.getResourceAsStream("SqlMapConfig.xml");
// 2.获取工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
// 3.获取sqlSession对象
sqlSession = sqlSessionFactory.openSession(true);
// 4.创建代理对象
iAccountDao = sqlSession.getMapper(IAccountDao.class);
} catch (Exception e) {
e.printStackTrace();
}
}

/**
* 释放资源
*/
@After // 用于在测试方法指定之后执行
public void destroy() {
try {
// 提交事务
sqlSession.commit();
// 释放资源
sqlSession.close();
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}

​​返回顶部​​


三、一对一查询(多对一)

需求: 查询所有账户信息,关联查询下单用户信息。

注意: 因为一个账户信息只能供某个用户使用,所以从查询账户信息出发关联查询用户信息为一对一查询。如 果从用户信息出发查询用户下的账户信息则为一对多查询,因为一个用户可以有多个账户。

3.1 编写sql语句

实现查询账户信息时,也要查询账户所对应的用户信息:
SELECT
a.*,
u.username,
u.address
FROM
account a,
user u
WHERE a.uid = u.id

在 MySQL 中测试的查询结果如下:

【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_mybatis_05,第5张

​​返回顶部​​


方式一:查询信息实体类

3.2.1 创建 AccountUser 类

为了能够封装上面 SQL 语句的查询结果,定义 AccountUser类中要包含账户信息同时还要包含用户信 息,所以我们要在定义 AccountUser 类时可以继承 Account 类。

package com.zyx.core.domain;

// 继承Account父类,包含其所有的属性
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 + '\'' +
'}';
}
}

3.2.2 IAccountDao

/**
* 查询所有账户,并且携带有用户的姓名、地址信息
* @return
*/
List<AccountUser> findAllAccount();

3.2.3 IAccountDao.xml 文件中的查询配置信息

<!--  查询所有账户信息并且包含用户信息  -->
<select id="findAllAccount" resultType="com.zyx.core.domain.AccountUser">
select a.*,u.username,u.address from account a,user u where a.UID=u.id;
</select>

3.2.4 AccountTest 测试类

@Test
public void findAllAccount() {
try {
// 1.执行查询所有方法
List<AccountUser> list = iAccountDao.findAllAccount();
for (AccountUser accountUser : list) {
System.out.println(accountUser);
}
} catch (Exception e) {
e.printStackTrace();
}
}

【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_学习笔记_06,第6张

​​返回顶部​​


方式二:添加主从关系对象属性

使用 resultMap,定义专门的 resultMap 用于映射一对一查询结果。

通过面向对象的关系可以得知,我们可以在 Account 类中加入一个 User 类的对象来代表这个账户 是哪个用户的。

3.3.1 修改 Account 类

public class Account implements Serializable {

......

private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}

......

}

3.3.2 修改 AccountDao 接口中的方法

/**
* 查询所有账户
* 注意:第二种方式,将返回值改 为了 Account 类型。
* 因为 Account 类中包含了一个 User 类的对象,它可以封装账户所对应的用户信息。
* @return
*/
List<Account> findAll();

3.3.3 重新定义 IAccountDao.xml 文件

<!-- 定义封装account和user的resultMap   -->
<resultMap id="accountUserMap" type="com.zyx.core.domain.Account">
<id property="ID" column="AID"></id>
<result property="UID" column="UID"></result>
<result property="MONEY" column="MONEY"></result>
<!-- 一对一的关系映射,配置封装user的内容
关联User表 通过UID 指明User类型 -->
<association property="user" column="UID" javaType="com.zyx.core.domain.User">
<id property="id" column="id"></id>
<result column="username" property="username"></result>
<result column="address" property="address"></result>
<result column="sex" property="sex"></result>
<result column="birthday" property="birthday"></result>
</association>
</resultMap>
<!-- 查询所有 -->
<select id="findAll" resultMap="accountUserMap">
select u.*,a.ID as AID,a.UID,a.MONEY from account a,user u where u.id = a.UID;
</select>

注意点:

  • association 部分定义了用户关联的账户信息。表示关联查询结果集
  • property=“user”: 关联查询的结果集存储在 Account 对象的上哪个属性。
  • javaType=“com.zyx.core.domain.User”: 指定关联查询的结果的对象类型即user对象属性类型;此处可以使用别名,也可以使用全限定名。不写该参数会报空指针,找不到封装到哪里。

3.3.4 测试

@Test
public void test_findAll() {
try {
// 1.执行查询所有方法
List<Account> list = iAccountDao.findAll();
for (Account account : list) {
System.out.println("");
System.out.println(account);
}
} catch (Exception e) {
e.printStackTrace();
}
}

【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_返回顶部_07,第7张

【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_学习笔记_08,第8张

​​返回顶部​​


四、一对多查询

需求: 查询所有用户信息及用户关联的账户信息。

分析: 用户信息和他的账户信息为一对多关系,并且查询过程中如果用户没有账户信息,此时也要将用户信息 查询出来,我们想到了左外连接查询比较合适。

4.1 编写sql语句

SELECT u.*, a.ID AID,a.UID,a.MONEY
FROM user u
LEFT JOIN account a
ON u.id = a.UID

测试该 SQL 语句在 MySQL 客户端工具的查询结果如下:

【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_用户信息_09,第9张


4.2 修改 User 类

public class User implements Serializable {

private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
// 一对多关系映射,主表实体应该包含从表实体的集合引用
private List<Account> accounts;

public List<Account> getAccounts() {
return accounts;
}

public void setAccounts(List<Account> accounts) {
this.accounts = accounts;
}
........
}

4.3 IUserDao

/**
* 查询所有用户信息,同时显示出账户信息
*
* @return
*/
List<User> findAll();

4.4 IUserDao.xml配置

<resultMap id="UserAccountMap" type="com.zyx.core.domain.User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="birthday" column="birthday"></result>
<result property="sex" column="sex"></result>
<result property="address" column="address"></result>
<!-- 配置User对象中accounts集合的映射 -->
<collection property="accounts" ofType="com.zyx.core.domain.Account">
<id property="ID" column="AID"></id>
<result property="UID" column="UID"></result>
<result property="MONEY" column="MONEY"></result>
</collection>
</resultMap>
<!-- 查询所有 -->
<select id="findAll" resultMap="UserAccountMap">
select u.*,a.ID AID,a.UID,a.MONEY from user u left join account a on u.id = a.UID
</select>

注意:

  • collection 部分定义了用户关联的账户信息。表示关联查询结果集
  • property=“accounts”: 关联查询的结果集存储在 User 对象的上哪个属性。
  • ofType=“com.zyx.core.domain.Account”: 指定关联查询的结果集中的对象类型即List中的对象类型。此处可以使用别名,也可以使用全限定名。

4.5 测试

@Test
public void test_findById() {
try {
// 查询单个用户
User user = iUserDao.findById(48);
System.out.println(user);
} catch (Exception e) {
e.printStackTrace();
}
}

【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_学习笔记_10,第10张

【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_用户信息_11,第11张

​​返回顶部​​


五、多对多查询

通过前面的学习,我们了解使用 Mybatis 实现一对一、一对多关系的维护;多对多关系其实我们看成是双向的一对多关系。

5.1 户与角色的关系模型

【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_用户信息_12,第12张

用户与角色的多对多关系模型如上图所示,简单来说就是利用中间的用户角色表(包含左右两表的各一个字段),通过中间表的信息将左右两表联系起来。

创建用户角色、角色表:

mysql> use ssm;
Database changed

mysql> DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
`ID` int(11) NOT NULL COMMENT '编号',
`ROLE_NAME` varchar(30) default NULL COMMENT '角色名称',
`ROLE_DESC` varchar(60) default NULL COMMENT '角色描述',
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert into `role`(`ID`,`ROLE_NAME`,`ROLE_DESC`)
values (1,'院长','管理整个学院'),
(2,'总裁','管理整个公司'),
(3,'校长','管理整个学校');

DROP TABLE IF EXISTS `user_role`;

CREATE TABLE `user_role` (
`UID` int(11) NOT NULL COMMENT '用户编号',
`RID` int(11) NOT NULL COMMENT '角色编号',
PRIMARY KEY (`UID`,`RID`),
KEY `FK_Reference_10` (`RID`),
CONSTRAINT `FK_Reference_10` FOREIGN KEY (`RID`) REFERENCES `role` (`ID`),
CONSTRAINT `FK_Reference_9` FOREIGN KEY (`UID`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert into `user_role`(`UID`,`RID`)
values (41,1),
(45,1),
(41,2);

Query OK, 0 rows affected (0.04 sec)

Query OK, 0 rows affected (0.07 sec)

Query OK, 3 rows affected (0.01 sec)
Records: 3 Duplicates: 0 Warnings: 0

Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.10 sec)
Query OK, 3 rows affected (0.01 sec)
Records: 3 Duplicates: 0 Warnings: 0

【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_学习笔记_13,第13张

​​返回顶部​​


5.2 业务要求及实现 SQL

需求: 实现查询所有对象并且加载它所分配的用户信息。

**分析: 查询角色我们需要用到Role表,但角色分配的用户的信息我们并不能直接找到用户信息,而是要通过中 间表(USER_ROLE 表)才能关联到用户信息。 **

【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_用户信息_14,第14张

基础配置:

  • 按照User类的配置,再配置一份Role的即可~
  • 【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_返回顶部_15,第15张

​​返回顶部​​


5.2.1 编写 SQL 语句

【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_sql_16,第16张

SELECT
r.*,
u.id uid,
u.username username,
u.birthday birthday,
u.sex sex,
u.address address
FROM
role r
LEFT JOIN
user_role ur
ON (r.ID = ur.RID)
LEFT JOIN
user u
ON (ur.UID = u.id)

运行效果:

【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_mybatis_17,第17张

​​返回顶部​​


5.2.2 编写角色实体类

public class Role implements Serializable {

// 数据库中以_分割,java中以驼峰式命名变量
private Integer roleId;
private String roleName;
private String roleDesc;
// 多对多的关系映射:一个角色可以赋予多个用户
private List<User> users;

.......
}

5.2.3 IRoleDao

public interface IRoleDao {
/**
* 查询所有角色
* @return
*/
List<Role> findAll();
}

5.2.4 IRoleDao.xml

<!-- 配置roleMap -->
<resultMap id="roleMap" type="com.zyx.core.domain.Role">
<id property="roleId" column="ID"></id>
<result property="roleName" column="ROLE_NAME"></result>
<result property="roleDesc" column="ROLE_DESC"></result>
<collection property="users" ofType="com.zyx.core.domain.User">
<id property="id" column="uid"></id>
<result property="username" column="username"></result>
<result property="birthday" column="birthday"></result>
<result property="sex" column="sex"></result>
<result property="address" column="address"></result>
</collection>
</resultMap>

<!-- 查询所有角色 -->
<select id="findAll" resultMap="roleMap">
SELECT r.*,u.id uid,u.username username,u.birthday birthday,u.sex sex,u.address address
FROM role r
LEFT JOIN
user_role ur
ON (r.ID = ur.RID)
LEFT JOIN
user u
ON (ur.UID = u.id);
</select>

5.2.5 测试

@Test
public void test_findAll() {
try {
// 1.执行查询所有方法
List<Role> list = iRoleDao.findAll();
for (Role role : list) {
System.out.println(role);
System.out.println(role.getUsers());
}
} catch (Exception e) {
e.printStackTrace();
}
}

【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_mybatis_18,第18张

​​返回顶部​​




文章目录

  • ​​Mybatis 多表查询​​
  • ​​一、表之间的关系​​
  • ​​二、准备工作​​
  • ​​2.1 创建account表​​
  • ​​2.2 创建Account、User实体类​​
  • ​​2.3 Dao层、映射文件配置​​
  • ​​2.4 主配置文件SqlMapConfig.xml​​
  • ​​2.5 测试类配置​​
  • ​​三、一对一查询(多对一)​​
  • ​​3.1 编写sql语句​​
  • ​​方式一:查询信息实体类​​
  • ​​3.2.1 创建 AccountUser 类​​
  • ​​3.2.2 IAccountDao​​
  • ​​3.2.3 IAccountDao.xml 文件中的查询配置信息​​
  • ​​3.2.4 AccountTest 测试类​​
  • ​​方式二:添加主从关系对象属性​​
  • ​​3.3.1 修改 Account 类​​
  • ​​3.3.2 修改 AccountDao 接口中的方法​​
  • ​​3.3.3 重新定义 IAccountDao.xml 文件​​
  • ​​3.3.4 测试​​
  • ​​四、一对多查询​​
  • ​​4.1 编写sql语句​​
  • ​​4.2 修改 User 类​​
  • ​​4.3 IUserDao​​
  • ​​4.4 IUserDao.xml配置​​
  • ​​4.5 测试​​
  • ​​五、多对多查询​​
  • ​​5.1 户与角色的关系模型​​
  • ​​5.2 业务要求及实现 SQL​​
  • ​​5.2.1 编写 SQL 语句​​
  • ​​5.2.2 编写角色实体类​​
  • ​​5.2.3 IRoleDao​​
  • ​​5.2.4 IRoleDao.xml​​
  • ​​5.2.5 测试​​

Mybatis 多表查询

一、表之间的关系

常见的表之间的对应关系:

  • 一对多
  • 多对一
  • 一对一
  • 多对多

举例:

  • 用户和订单就是一对多
  • 订单和用户就是多对一
  • 一个用户可以下多个订单
  • 多个订单属于同一个用
  • 人和身份证号就是一对一
  • 一个人只能有一个身份证号
  • 一个身份证号只能属于一个人
  • 老师和学生之间就是多对多
  • 一个学生可以被多个老师教过
  • 一个老师可以交多个学生
  • 特例:
  • 如果拿出每一个订单,他都只能属于一个用户;所以 MyBatis 就把 多对一 看成了 一对一。

​​返回顶部​​


二、准备工作

【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_学习笔记,第1张

2.1 创建account表

mysql> use ssm;
Database changed
mysql> 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 `account`(`ID`,`UID`,`MONEY`) values (1,46,1000),(2,45,1000),(3,46,2000);
Query OK, 0 rows affected (0.01 sec)
Query OK, 0 rows affected (0.16 sec)
Query OK, 3 rows affected (0.01 sec)
Records: 3 Duplicates: 0 Warnings: 0

mysql> select * from account;
+----+-----+-------+
| ID | UID | MONEY |
+----+-----+-------+
| 1 | 46 | 1000 |
| 2 | 45 | 1000 |
| 3 | 46 | 2000 |
+----+-----+-------+
3 rows in set (0.04 sec)

​​返回顶部​​


2.2 创建Account、User实体类

  • 注意字段的对应
  • 【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_sql_02,第2张

  • ​​返回顶部​​

2.3 Dao层、映射文件配置

  • 配置最基本的 findAll() 查询接口、sql
  • 【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_sql_03,第3张

  • ​​返回顶部​​

2.4 主配置文件SqlMapConfig.xml

  • 配置主配置的映射文件路径,也可以使用package标签使用包路径的扫描
  • 【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_学习笔记_04,第4张

  • ​​返回顶部​​

2.5 测试类配置

import com.zyx.core.dao.IAccountDao;
import com.zyx.core.dao.IUserDao;
import com.zyx.core.domain.Account;
import com.zyx.core.domain.AccountUser;
import com.zyx.core.domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

public class AccountTest {

InputStream in = null;
SqlSession sqlSession;
IAccountDao iAccountDao;

/**
* 初始化方法
*/
@Before // 用于在测试方法执行之前执行
public void init() {
try {
// 1.读取主配置文件
in = Resources.getResourceAsStream("SqlMapConfig.xml");
// 2.获取工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
// 3.获取sqlSession对象
sqlSession = sqlSessionFactory.openSession(true);
// 4.创建代理对象
iAccountDao = sqlSession.getMapper(IAccountDao.class);
} catch (Exception e) {
e.printStackTrace();
}
}

/**
* 释放资源
*/
@After // 用于在测试方法指定之后执行
public void destroy() {
try {
// 提交事务
sqlSession.commit();
// 释放资源
sqlSession.close();
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}

​​返回顶部​​


三、一对一查询(多对一)

需求: 查询所有账户信息,关联查询下单用户信息。

注意: 因为一个账户信息只能供某个用户使用,所以从查询账户信息出发关联查询用户信息为一对一查询。如 果从用户信息出发查询用户下的账户信息则为一对多查询,因为一个用户可以有多个账户。

3.1 编写sql语句

实现查询账户信息时,也要查询账户所对应的用户信息:
SELECT
a.*,
u.username,
u.address
FROM
account a,
user u
WHERE a.uid = u.id

在 MySQL 中测试的查询结果如下:

【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_mybatis_05,第5张

​​返回顶部​​


方式一:查询信息实体类

3.2.1 创建 AccountUser 类

为了能够封装上面 SQL 语句的查询结果,定义 AccountUser类中要包含账户信息同时还要包含用户信 息,所以我们要在定义 AccountUser 类时可以继承 Account 类。

package com.zyx.core.domain;

// 继承Account父类,包含其所有的属性
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 + '\'' +
'}';
}
}

3.2.2 IAccountDao

/**
* 查询所有账户,并且携带有用户的姓名、地址信息
* @return
*/
List<AccountUser> findAllAccount();

3.2.3 IAccountDao.xml 文件中的查询配置信息

<!--  查询所有账户信息并且包含用户信息  -->
<select id="findAllAccount" resultType="com.zyx.core.domain.AccountUser">
select a.*,u.username,u.address from account a,user u where a.UID=u.id;
</select>

3.2.4 AccountTest 测试类

@Test
public void findAllAccount() {
try {
// 1.执行查询所有方法
List<AccountUser> list = iAccountDao.findAllAccount();
for (AccountUser accountUser : list) {
System.out.println(accountUser);
}
} catch (Exception e) {
e.printStackTrace();
}
}

【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_学习笔记_06,第6张

​​返回顶部​​


方式二:添加主从关系对象属性

使用 resultMap,定义专门的 resultMap 用于映射一对一查询结果。

通过面向对象的关系可以得知,我们可以在 Account 类中加入一个 User 类的对象来代表这个账户 是哪个用户的。

3.3.1 修改 Account 类

public class Account implements Serializable {

......

private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}

......

}

3.3.2 修改 AccountDao 接口中的方法

/**
* 查询所有账户
* 注意:第二种方式,将返回值改 为了 Account 类型。
* 因为 Account 类中包含了一个 User 类的对象,它可以封装账户所对应的用户信息。
* @return
*/
List<Account> findAll();

3.3.3 重新定义 IAccountDao.xml 文件

<!-- 定义封装account和user的resultMap   -->
<resultMap id="accountUserMap" type="com.zyx.core.domain.Account">
<id property="ID" column="AID"></id>
<result property="UID" column="UID"></result>
<result property="MONEY" column="MONEY"></result>
<!-- 一对一的关系映射,配置封装user的内容
关联User表 通过UID 指明User类型 -->
<association property="user" column="UID" javaType="com.zyx.core.domain.User">
<id property="id" column="id"></id>
<result column="username" property="username"></result>
<result column="address" property="address"></result>
<result column="sex" property="sex"></result>
<result column="birthday" property="birthday"></result>
</association>
</resultMap>
<!-- 查询所有 -->
<select id="findAll" resultMap="accountUserMap">
select u.*,a.ID as AID,a.UID,a.MONEY from account a,user u where u.id = a.UID;
</select>

注意点:

  • association 部分定义了用户关联的账户信息。表示关联查询结果集
  • property=“user”: 关联查询的结果集存储在 Account 对象的上哪个属性。
  • javaType=“com.zyx.core.domain.User”: 指定关联查询的结果的对象类型即user对象属性类型;此处可以使用别名,也可以使用全限定名。不写该参数会报空指针,找不到封装到哪里。

3.3.4 测试

@Test
public void test_findAll() {
try {
// 1.执行查询所有方法
List<Account> list = iAccountDao.findAll();
for (Account account : list) {
System.out.println("");
System.out.println(account);
}
} catch (Exception e) {
e.printStackTrace();
}
}

【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_返回顶部_07,第7张

【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_学习笔记_08,第8张

​​返回顶部​​


四、一对多查询

需求: 查询所有用户信息及用户关联的账户信息。

分析: 用户信息和他的账户信息为一对多关系,并且查询过程中如果用户没有账户信息,此时也要将用户信息 查询出来,我们想到了左外连接查询比较合适。

4.1 编写sql语句

SELECT u.*, a.ID AID,a.UID,a.MONEY
FROM user u
LEFT JOIN account a
ON u.id = a.UID

测试该 SQL 语句在 MySQL 客户端工具的查询结果如下:

【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_用户信息_09,第9张


4.2 修改 User 类

public class User implements Serializable {

private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
// 一对多关系映射,主表实体应该包含从表实体的集合引用
private List<Account> accounts;

public List<Account> getAccounts() {
return accounts;
}

public void setAccounts(List<Account> accounts) {
this.accounts = accounts;
}
........
}

4.3 IUserDao

/**
* 查询所有用户信息,同时显示出账户信息
*
* @return
*/
List<User> findAll();

4.4 IUserDao.xml配置

<resultMap id="UserAccountMap" type="com.zyx.core.domain.User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="birthday" column="birthday"></result>
<result property="sex" column="sex"></result>
<result property="address" column="address"></result>
<!-- 配置User对象中accounts集合的映射 -->
<collection property="accounts" ofType="com.zyx.core.domain.Account">
<id property="ID" column="AID"></id>
<result property="UID" column="UID"></result>
<result property="MONEY" column="MONEY"></result>
</collection>
</resultMap>
<!-- 查询所有 -->
<select id="findAll" resultMap="UserAccountMap">
select u.*,a.ID AID,a.UID,a.MONEY from user u left join account a on u.id = a.UID
</select>

注意:

  • collection 部分定义了用户关联的账户信息。表示关联查询结果集
  • property=“accounts”: 关联查询的结果集存储在 User 对象的上哪个属性。
  • ofType=“com.zyx.core.domain.Account”: 指定关联查询的结果集中的对象类型即List中的对象类型。此处可以使用别名,也可以使用全限定名。

4.5 测试

@Test
public void test_findById() {
try {
// 查询单个用户
User user = iUserDao.findById(48);
System.out.println(user);
} catch (Exception e) {
e.printStackTrace();
}
}

【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_学习笔记_10,第10张

【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_用户信息_11,第11张

​​返回顶部​​


五、多对多查询

通过前面的学习,我们了解使用 Mybatis 实现一对一、一对多关系的维护;多对多关系其实我们看成是双向的一对多关系。

5.1 户与角色的关系模型

【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_用户信息_12,第12张

用户与角色的多对多关系模型如上图所示,简单来说就是利用中间的用户角色表(包含左右两表的各一个字段),通过中间表的信息将左右两表联系起来。

创建用户角色、角色表:

mysql> use ssm;
Database changed

mysql> DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
`ID` int(11) NOT NULL COMMENT '编号',
`ROLE_NAME` varchar(30) default NULL COMMENT '角色名称',
`ROLE_DESC` varchar(60) default NULL COMMENT '角色描述',
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert into `role`(`ID`,`ROLE_NAME`,`ROLE_DESC`)
values (1,'院长','管理整个学院'),
(2,'总裁','管理整个公司'),
(3,'校长','管理整个学校');

DROP TABLE IF EXISTS `user_role`;

CREATE TABLE `user_role` (
`UID` int(11) NOT NULL COMMENT '用户编号',
`RID` int(11) NOT NULL COMMENT '角色编号',
PRIMARY KEY (`UID`,`RID`),
KEY `FK_Reference_10` (`RID`),
CONSTRAINT `FK_Reference_10` FOREIGN KEY (`RID`) REFERENCES `role` (`ID`),
CONSTRAINT `FK_Reference_9` FOREIGN KEY (`UID`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert into `user_role`(`UID`,`RID`)
values (41,1),
(45,1),
(41,2);

Query OK, 0 rows affected (0.04 sec)

Query OK, 0 rows affected (0.07 sec)

Query OK, 3 rows affected (0.01 sec)
Records: 3 Duplicates: 0 Warnings: 0

Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.10 sec)
Query OK, 3 rows affected (0.01 sec)
Records: 3 Duplicates: 0 Warnings: 0

【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_学习笔记_13,第13张

​​返回顶部​​


5.2 业务要求及实现 SQL

需求: 实现查询所有对象并且加载它所分配的用户信息。

**分析: 查询角色我们需要用到Role表,但角色分配的用户的信息我们并不能直接找到用户信息,而是要通过中 间表(USER_ROLE 表)才能关联到用户信息。 **

【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_用户信息_14,第14张

基础配置:

  • 按照User类的配置,再配置一份Role的即可~
  • 【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_返回顶部_15,第15张

​​返回顶部​​


5.2.1 编写 SQL 语句

【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_sql_16,第16张

SELECT
r.*,
u.id uid,
u.username username,
u.birthday birthday,
u.sex sex,
u.address address
FROM
role r
LEFT JOIN
user_role ur
ON (r.ID = ur.RID)
LEFT JOIN
user u
ON (ur.UID = u.id)

运行效果:

【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_mybatis_17,第17张

​​返回顶部​​


5.2.2 编写角色实体类

public class Role implements Serializable {

// 数据库中以_分割,java中以驼峰式命名变量
private Integer roleId;
private String roleName;
private String roleDesc;
// 多对多的关系映射:一个角色可以赋予多个用户
private List<User> users;

.......
}

5.2.3 IRoleDao

public interface IRoleDao {
/**
* 查询所有角色
* @return
*/
List<Role> findAll();
}

5.2.4 IRoleDao.xml

<!-- 配置roleMap -->
<resultMap id="roleMap" type="com.zyx.core.domain.Role">
<id property="roleId" column="ID"></id>
<result property="roleName" column="ROLE_NAME"></result>
<result property="roleDesc" column="ROLE_DESC"></result>
<collection property="users" ofType="com.zyx.core.domain.User">
<id property="id" column="uid"></id>
<result property="username" column="username"></result>
<result property="birthday" column="birthday"></result>
<result property="sex" column="sex"></result>
<result property="address" column="address"></result>
</collection>
</resultMap>

<!-- 查询所有角色 -->
<select id="findAll" resultMap="roleMap">
SELECT r.*,u.id uid,u.username username,u.birthday birthday,u.sex sex,u.address address
FROM role r
LEFT JOIN
user_role ur
ON (r.ID = ur.RID)
LEFT JOIN
user u
ON (ur.UID = u.id);
</select>

5.2.5 测试

@Test
public void test_findAll() {
try {
// 1.执行查询所有方法
List<Role> list = iRoleDao.findAll();
for (Role role : list) {
System.out.println(role);
System.out.println(role.getUsers());
}
} catch (Exception e) {
e.printStackTrace();
}
}

【MyBatis】Mybatis 多表查询,【MyBatis】Mybatis 多表查询_mybatis_18,第18张

​​返回顶部​​




https://www.xamrdz.com/lan/5qs1924535.html

相关文章: