Mybatis入门:4(多表查询操作)

多表查询操作

Mybatis的多表操作

表之间的关系有几种:一对多、一对一、多对一、多对多
举例:
用户和订单就是一对多——一个用户可以下多个订单
订单和用户就是多对一——多个订单属于同一个用户

人和身份证号就是一对一
一个人只能有一个身份证号
一个身份证号只能属于一个人

老师和学生之间就是多对多
一个学生可以被多个老师教过
一个老师可以教多个学生
特例:
如果拿出每-一个订单,他都只能属于一个用户。
所以Mybatis就把多对一看成了一对一。

我们首先建立了两个新的表格方便操作,如下:
account表格:
在这里插入图片描述
user表格:
在这里插入图片描述

mybatis中的多表查询:

示例:用户和账户
一个用户可以有多个账户
一个账户只能属于一个用户(多个账户也可以属于同一个用户)

步骤:

  1. 建立两张表:用户表,账户表
    让用户表和账户表之间具备一对多的关系:需要使用外键在账户表中添加
    MySQL外键的作用:主要目的是控制存储在外键表中的数据。使两张表形成关联,外键只能引用外表中列的值!
    当创建或更改表时可通过定义 FOREIGN KEY 约束来创建外键
  2. 建立两个实体类:用户实体类和账户实体类
    让用户和账户的实体类能体现出啦一-对多的关系
  3. 建立两个配置文件
    用户的配置文件
    账户的配置文件
  4. 实现配置:
    当我们查询用户时,可以同时得到用户下所包含的账户信息
    当我们查询账户时,可以同时得到账户的所属用户信息

一对一操作

一.通过写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. 建立两张表:用户表,角色表
    让用户表和角色表具有多对多的关系。需要使用中间表,中间表中包含各自的主键,在中间表中是外键。
  2. 建立两个实体类:用户实体类和角色实体类
    让用户和角色的实体类能体现出来多对多的关系
    各自包含对方一个集合引用
  3. 建立两个配置文件
    用户的配置文件
    角色的配置文件
  4. 实现配置:
    当我们查询用户时,可以同时得到用户所包含的角色信息
    当我们查询角色时,可以同时得到角色的所赋予的用户信息
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());
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值