多表查询操作
Mybatis的多表操作
表之间的关系有几种:一对多、一对一、多对一、多对多
举例:
用户和订单就是一对多——一个用户可以下多个订单
订单和用户就是多对一——多个订单属于同一个用户
人和身份证号就是一对一
一个人只能有一个身份证号
一个身份证号只能属于一个人
老师和学生之间就是多对多
一个学生可以被多个老师教过
一个老师可以教多个学生
特例:
如果拿出每-一个订单,他都只能属于一个用户。
所以Mybatis就把多对一看成了一对一。
我们首先建立了两个新的表格方便操作,如下:
account表格:
user表格:
mybatis中的多表查询:
示例:用户和账户
一个用户可以有多个账户
一个账户只能属于一个用户(多个账户也可以属于同一个用户)
步骤:
- 建立两张表:用户表,账户表
让用户表和账户表之间具备一对多的关系:需要使用外键在账户表中添加
MySQL外键的作用:主要目的是控制存储在外键表中的数据。使两张表形成关联,外键只能引用外表中列的值!
当创建或更改表时可通过定义 FOREIGN KEY 约束来创建外键 - 建立两个实体类:用户实体类和账户实体类
让用户和账户的实体类能体现出啦一-对多的关系 - 建立两个配置文件
用户的配置文件
账户的配置文件 - 实现配置:
当我们查询用户时,可以同时得到用户下所包含的账户信息
当我们查询账户时,可以同时得到账户的所属用户信息
一对一操作
一.通过写Account子类的方式查询(不太常用)
<!--查询所有账户同时包含用户名和地址信息-->
<select id="findAllAccount" resultType="accountuser">
select a.*,u.username,u.address from account a , user u
where u.id = a.uid;
</select>
Account类
package com.domain;
import java.io.Serializable;
public class Account implements Serializable {
private Integer id;
private Integer uid; //外键
private Double money;
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 +
'}';
}
}
AccountUser类(Account子类)
package com.domain;
public class AccountUser extends Account { //继承了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{" + //super.toString()调用父类的toString()方法
"username='" + username + '\'' +
", address='" + address + '\'' +
'}';
}
}
User类
package com.domain;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
public class User implements Serializable {
private Integer id;
private String username;
private String address;
private String sex;
private Date birthday;
//一对多关系映射:主表实体应该包含从表实体的集合引用
private List<Account> accounts;
public List<Account> getAccounts() {
return accounts;
}
public void setAccounts(List<Account> accounts) {
this.accounts = accounts;
}
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 String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", address='" + address + '\'' +
", sex='" + sex + '\'' +
", birthday=" + birthday +
'}';
}
}
测试类
/**
* 测试查询所有账户,同时包含用户名称和地址
*/
@Test
public void testFindAllAccountUser(){
List<AccountUser> aus = accountDao.findAllAccount();
for(AccountUser au : aus){
System.out.println(au);
}
}
结果:
大概思路
1.测试类findAllAccount()方法返回AccountUser集合,输出集合
2.执行findAllAccount()方法,转入xml配置文件,执行sql语句查询
3.返回AccountUser类型的查询结果,执行子类的toString方法
4.super.toString()执行父类的toString方法
二.通过建立实体类关系的方式(常用)
<!-- 定义封装account和user的resultMap -->
<!-- 一对一的关系映射:配置封装user的内容-->
<resultMap id="accountUserMap" type="account">
<id property="id" column="aid"/> <!--此处的aid为表中id的别名-->
<result property="uid" column="uid"/>
<result property="money" column="money"/>
<association property="user" javaType="user"> <!--由于使用了别名,所以直接写user就行了-->
<!--为了防止我们开发出错,在没有特别要求的情况下,column名可以完全和property名称一致,否则当我们没有对应上的时候,数据库匹配不到-->
<id property="id" column="id"/>
<result column="username" property="username"/>
<result column="address" property="address"/>
<result column="sex" property="sex"/>
<result column="birthday" property="birthday"/>
</association>
</resultMap>
<!-- 查询所有 -->
<select id="findAll" resultMap="accountUserMap">
<!-- as可理解为:用作、当成,作用;一般是重命名列名或者表名。(主要为了查询方便)-->
select u.*,a.id as aid,a.uid,a.money from account a,user u where u.id = a.uid;
</select>
association标签的作用:就是将另一张表的字段关联过来 然后一起映射到实体类。
Account类(在之前的基础上改造)
package com.domain;
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 +
'}';
}
}
User类(跟上面一样,不变)
测试类
@Test
public void testFindAll(){
List<Account> accounts = accountDao.findAll();
for(Account account : accounts){
System.out.println("--------每个account的信息------------");
System.out.println(account);
System.out.println(account.getUser());//其实可以直接在Account类那里将toString()方法重写一遍,加上user,就不用调用getUser()方法了
}
}
结果:
一对多操作
一个用户存在多个账户的情况
<!-- 定义User的resultMap-->
<!--一对多查询-->
<resultMap id="userAccountMap" type="user">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="address" column="address"/>
<result property="sex" column="sex"/>
<result property="birthday" column="birthday"/>
<!-- 配置user对象中accounts集合的映射 -->
<collection property="accounts" ofType="account"> <!--ofType指的是集合accounts的类型-->
<id column="aid" property="id"/> <!--aid为列别名,起别名是因为主子表都有该字段-->
<result column="uid" property="uid"/>
<result column="money" property="money"/>
</collection>
</resultMap>
<!-- 查询所有 -->
<select id="findAll" resultMap="userAccountMap">
<!-- left join(左联接)返回包括左表(user)中的所有记录和右表(account)中联结字段相等(即u.id = a.uid)的记录,即返回user表和满足u.id = a.uid条件的account表 -->
select * from user u left outer join account a on u.id = a.uid
</select>
注:
- left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录
- right join(右联接) 返回包括右表中的所有记录和左表中联结字段相等的记录
- inner join(等值连接) 只返回两个表中联结字段相等的行
- outer join(外连接) 可分为左外连接left outer join和右外连接right outer join
上面的left join(左联结)表示返回所有user表和满足u.id = a.uid条件的account表内容
User类(添加上了Account集合属性)
package com.domain;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
public class User implements Serializable {
private Integer id;
private String username;
private String address;
private String sex;
private Date birthday;
//一对多关系映射:主表实体应该包含从表实体的集合引用
private List<Account> accounts;
public List<Account> getAccounts() {
return accounts;
}
public void setAccounts(List<Account> accounts) {
this.accounts = accounts;
}
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 String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", address='" + address + '\'' +
", sex='" + sex + '\'' +
", birthday=" + birthday +
'}';
}
}
测试类
@Test
public void testFindAll(){
List<User> users = userDao.findAll();
for(User user : users){
System.out.println("-----每个用户的信息------");
System.out.println(user);
System.out.println(user.getAccounts());
}
}
结果:
多对多操作
示例:用户和角色
一个用户可以有多个角色
一个角色可以赋予多个用户
步骤:
- 建立两张表:用户表,角色表
让用户表和角色表具有多对多的关系。需要使用中间表,中间表中包含各自的主键,在中间表中是外键。 - 建立两个实体类:用户实体类和角色实体类
让用户和角色的实体类能体现出来多对多的关系
各自包含对方一个集合引用 - 建立两个配置文件
用户的配置文件
角色的配置文件 - 实现配置:
当我们查询用户时,可以同时得到用户所包含的角色信息
当我们查询角色时,可以同时得到角色的所赋予的用户信息
1.查询角色获取角色下所包含的用户信息
<!--定义role表的resultMap-->
<resultMap id="roleMap" type="role">
<id property="roleId" column="rid"/>
<result property="roleName" column="role_name"/>
<result property="roleDesc" column="role_desc"/>
<collection property="users" ofType="user">
<id column="id" property="id"/>
<result column="username" property="username"/>
<result column="address" property="address"/>
<result column="sex" property="sex"/>
<result column="birthday" property="birthday"/>
</collection>
</resultMap>
<!--查询所有-->
<select id="findAll" resultMap="roleMap">
select u.*,r.id as rid,r.role_name,role_desc from role r
left outer join user_role ur on r.id=ur.rid
left outer join user u on u.id=ur.uid
</select>
多对多查询的精华基本都在sql语句的书写上面了…
Role类
package com.domain;
import java.io.Serializable;
import java.util.List;
public class Role implements Serializable {
private Integer roleId;
private String roleName;
private String roleDesc;
private List<User> users;
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
public Integer getRoleId() {
return roleId;
}
public void setRoleId(Integer roleId) {
this.roleId = roleId;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public String getRoleDesc() {
return roleDesc;
}
public void setRoleDesc(String roleDesc) {
this.roleDesc = roleDesc;
}
@Override
public String toString() {
return "Role{" +
"roleId=" + roleId +
", roleName='" + roleName + '\'' +
", roleDesc='" + roleDesc + '\'' +
'}';
}
}
User类
package com.domain;
import java.io.Serializable;
import java.util.Date;
public class User implements Serializable {
private Integer id;
private String username;
private String address;
private String sex;
private Date birthday;
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 String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", address='" + address + '\'' +
", sex='" + sex + '\'' +
", birthday=" + birthday +
'}';
}
}
测试类
@Test
public void testFindAll(){
List<Role> roles = roleDao.findAll();
for(Role role : roles){
System.out.println("-----每个角色的信息------");
System.out.println(role);
System.out.println(role.getUsers());
}
}
结果:
2.查询用户获取用户所包含的角色信息
<!--多对多查询-->
<resultMap id="userMap" type="user">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="address" column="address"/>
<result property="sex" column="sex"/>
<result property="birthday" column="birthday"/>
<!--配置角色集合的映射-->
<collection property="roles" ofType="role">
<id property="roleId" column="rid"/>
<result property="roleName" column="role_name"/>
<result property="roleDesc" column="role_desc"/>
</collection>
</resultMap>
<!-- 查询所有 -->
<select id="findAll" resultMap="userMap">
select u.*,r.id as rid,r.role_name,role_desc from user u
left outer join user_role ur on u.id=ur.uid
left outer join role r on r.id=ur.rid
</select>
通过观察我们可以发现UserDao的配置文件中的sql查询语句刚好是和上面查询角色时的反过来的。
Role类不变
User类(加上Role类型的集合属性)
package com.domain;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
public class User implements Serializable {
private Integer id;
private String username;
private String address;
private String sex;
private Date birthday;
//多对多的关系映射:一个用户可以具备多个角色
private List<Role>roles;
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
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 String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", address='" + address + '\'' +
", sex='" + sex + '\'' +
", birthday=" + birthday +
'}';
}
}
测试类
@Test
public void testFindAll(){
List<User> users = userDao.findAll();
for(User user : users){
System.out.println("-----每个用户的信息------");
System.out.println(user);
System.out.println(user.getRoles());
}
}