文章目录
- 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 就把 多对一 看成了 一对一。
返回顶部
二、准备工作
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实体类
- 注意字段的对应
- 返回顶部
2.3 Dao层、映射文件配置
- 配置最基本的 findAll() 查询接口、sql
- 返回顶部
2.4 主配置文件SqlMapConfig.xml
- 配置主配置的映射文件路径,也可以使用package标签使用包路径的扫描
- 返回顶部
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 中测试的查询结果如下:
返回顶部
方式一:查询信息实体类
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();
}
}
返回顶部
方式二:添加主从关系对象属性
使用 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();
}
}
返回顶部
四、一对多查询
需求: 查询所有用户信息及用户关联的账户信息。
分析: 用户信息和他的账户信息为一对多关系,并且查询过程中如果用户没有账户信息,此时也要将用户信息 查询出来,我们想到了左外连接查询比较合适。
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 客户端工具的查询结果如下:
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 实现一对一、一对多关系的维护;多对多关系其实我们看成是双向的一对多关系。
5.1 户与角色的关系模型
用户与角色的多对多关系模型如上图所示,简单来说就是利用中间的用户角色表(包含左右两表的各一个字段),通过中间表的信息将左右两表联系起来。
创建用户角色、角色表:
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
返回顶部
5.2 业务要求及实现 SQL
需求: 实现查询所有对象并且加载它所分配的用户信息。
**分析: 查询角色我们需要用到Role表,但角色分配的用户的信息我们并不能直接找到用户信息,而是要通过中 间表(USER_ROLE 表)才能关联到用户信息。 **
基础配置:
- 按照User类的配置,再配置一份Role的即可~
返回顶部
5.2.1 编写 SQL 语句
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)
运行效果:
返回顶部
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();
}
}
返回顶部
文章目录
- 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 就把 多对一 看成了 一对一。
返回顶部
二、准备工作
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实体类
- 注意字段的对应
- 返回顶部
2.3 Dao层、映射文件配置
- 配置最基本的 findAll() 查询接口、sql
- 返回顶部
2.4 主配置文件SqlMapConfig.xml
- 配置主配置的映射文件路径,也可以使用package标签使用包路径的扫描
- 返回顶部
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 中测试的查询结果如下:
返回顶部
方式一:查询信息实体类
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();
}
}
返回顶部
方式二:添加主从关系对象属性
使用 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();
}
}
返回顶部
四、一对多查询
需求: 查询所有用户信息及用户关联的账户信息。
分析: 用户信息和他的账户信息为一对多关系,并且查询过程中如果用户没有账户信息,此时也要将用户信息 查询出来,我们想到了左外连接查询比较合适。
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 客户端工具的查询结果如下:
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 实现一对一、一对多关系的维护;多对多关系其实我们看成是双向的一对多关系。
5.1 户与角色的关系模型
用户与角色的多对多关系模型如上图所示,简单来说就是利用中间的用户角色表(包含左右两表的各一个字段),通过中间表的信息将左右两表联系起来。
创建用户角色、角色表:
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
返回顶部
5.2 业务要求及实现 SQL
需求: 实现查询所有对象并且加载它所分配的用户信息。
**分析: 查询角色我们需要用到Role表,但角色分配的用户的信息我们并不能直接找到用户信息,而是要通过中 间表(USER_ROLE 表)才能关联到用户信息。 **
基础配置:
- 按照User类的配置,再配置一份Role的即可~
返回顶部
5.2.1 编写 SQL 语句
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)
运行效果:
返回顶部
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();
}
}
返回顶部