MyBatis多表操作
经过了 MyBatis 基本增删改查的学习,而在实际的项目中,我们往往会接触到多表的操作,什么是多表呢, 在实际生活中,每个实体之间往往是存在关系的,而我们的项目却是要依赖数据库将这些实体之间的关系串联起来,从而实现我们的业务,所以这部分,我们着重讲解如何使用 MyBatis 框架处理多张数据表之间的联系,帮助我们更加理解数据库的映射关系
(一) 表间关系
A:一对多
- 用户和订单/理财产品
- 一个用户可以买好几个批次的理财产品
- 部门和员工
- 一个部门可以有很多员工
B:多对一
- 订单和用户
- 多个订单属于同一个用户
C:多对多
- 学生选课和学生
- 一个学生可以选择多门课,一门课可以被多个学生选择
D:一对一
- 身份证、护照等证件
- 一个证件只能属于一个人
可以看到,第二章内容我们直接进入了业务表的内容,而由于前几篇文章的铺垫,我将User的相关信息都没有讲解,缺失的内容只有用户实体类,以及对应 XML 映射文件,这个非常简单 以及对应测试类
(二) 根据业务创建表
文章中我们使用用户和账户之间的账户的关系,即:
- 一个用户可以拥有多个账户,一个账户只能属于一个用户,多个账户也可以属于同一个用户
首先需要建立两张表:用户表和账户表
- 让两者分别具备一对多的关系,我们需要在账户表中添加外键
User表
CREATE TABLE USER (
`id` INT(11)NOT NULL AUTO_INCREMENT,
`username` VARCHAR(32) NOT NULL COMMENT '用户名',
`telephone` VARCHAR(11) NOT NULL COMMENT '手机',
`birthday` DATETIME DEFAULT NULL COMMENT '生日',
`gender` CHAR(1) DEFAULT NULL COMMENT '性别',
`address` VARCHAR(256) DEFAULT NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
复制代码
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;
复制代码
(三) 账户表-单表查询
首先创建其对应Account实体类
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money;
......对应 get set 方法
}
复制代码
在其 AccountMappre 接口中增加查询所有的方法
public interface AccountMapper {
/**
* 查询所有账户
* @return
*/
List<Account> findAll();
}
复制代码
增加其映射文件,注:省略头部的一些引入代码
<mapper namespace="cn.ideal.mapper.AccountMapper">
<!-- 根据查询所有用户 -->
<select id="findAll" resultType="Account">
select * from account
</select>
</mapper>
复制代码
还是要再多啰嗦一句,resultType="Account"
这里是因为我们在主配置文件中已经,对omain中类都起了别名,所以可以直接用包下的类名,如果不了解的朋友,使用全类名也是一样的
测试一下:
/**
* 测试查询所有
*/
@Test
public void testFindAll(){
List<Account> accounts = accountMapper.findAll();
for (Account account : accounts){
System.out.println(account);
}
}
复制代码
看一下效果:
(四) Account 一对一查询
如何查询到 Acount 中信息的同时,根据用户的 id 值将对应的数据显示出来,这其实主要就是需要改变 SQL 的写法,我们在本地的 MySQL中先试一试
SELECT FROM account a,user u WHERE u.id=a.uid;
复制代码
执行结果
结果出来了,但是 user 表中的 id 属性由于和 account 表中的 id 属性名称是一致的,所以自动起了别名,更好的做法是,我们自己设置其对应的别名
SELECT u.*,a.id as aid,a.uid,a.money FROM account a,user u WHERE u.id=a.uid;
复制代码
这样看起来就条理了许多
到了这一步,我们就可以在代码中实现这样的功能了,即通过查询账户信息,同时查询出对应的用户信息,那由于注册时间,男女等信息,我并不想要,怎么办呢?我们可以再加一点约束,用户的信息只显示名称和地址两个字段
A:创建子类方式(不算太常用)
(1) 修改 Account 接口
/**
* 查询所有账户,并且带有用户名称和地址信息
* @return
*/
List<UserAccount> findAllAccount();
复制代码
大家可能注意到我们返回的 List 类型为 UserAccount,这是为什么呢?
既然我们想返回的信息中,需要包含两个表中的信息,似乎我们并没有一个实体可以承载这么多信息,所以我们创建一个 UserAccount 类
(2) 创建 UserAccount 类
public class UserAccount extends Account {
private String username;
private String address;
......对应 get set 方法
@Override
public String toString() {
return super.toString() + " UserAccount{" +
"username='" + username + '\'' +
", address='" + address + '\'' +
'}';
}
}
复制代码
说明:由于我们只需要显示 名称 和 地址 这两个字段,所以只需要创建 username 和 address 两个字段就可以了,而继承 Account 可以方便我们调用输出查询到账户中的信息
(3) 修改 AccountMapper.xml
<select id="findAllAccount" resultType="UserAccount">
select a.*,u.username,u.address from account a , user u where u.id = a.uid;
</select>
复制代码
(4) 测试代码
/**
* 查询所有账户,并且带有用户名称和地址信息
* @return
*/
@Test
public void testFindAllAccount(){
List<UserAccount> uas