Mybatis入门笔记(7)——多表操作之一对一

多表操作

举例说明

多对一:

用户和订单是一对多,一个用户可以下多个订单;

订单和用户是多对一,多个订单属于同一个用户。

一对一:

人和身份证号。一个人只能有一个身份证号,一个身份证号也只能被一个人所有。

多对多:

老师和学生之间。一个学生可以被多个老师教过,一个老师可以交多个学生。

开始之前

  1. 新建两张表:User表和Account表;user.sql和accout.sql;

    两张表具备一对多的关系,需要使用外键在账户表中添加

  2. 建立两个实体类:用户实体类和账户实体类

    让用户和账户的实体类能体现出一对多的关系

  3. 建立两个配置文件

    用户的配置文件:IUSerDao.xml

    账户的配置文件:IAccountDao.xml

  4. 实现功能:

    当查询用户时,得到用户下所属的账户信息(一对多关系)

    当查询账户时,得到账户的所属用户信息(一对一关系)

之前的案例中,我们已经得到了User的相关信息,所以这次只需要配置账户的信息。

  1. 新建一个account表

    SET NAMES utf8mb4;
    SET FOREIGN_KEY_CHECKS = 0;
    
    -- ----------------------------
    -- Table structure for account
    -- ----------------------------
    DROP TABLE IF EXISTS `account`;
    CREATE TABLE `account`  (
      `id` int(11) NOT NULL COMMENT '编号',
      `uid` int(11) NULL DEFAULT NULL COMMENT '用户编号',
      `money` double NULL DEFAULT NULL COMMENT '金额',
      PRIMARY KEY (`id`) USING BTREE,
      INDEX `FK_Reference_8`(`uid`) USING BTREE,
      CONSTRAINT `FK_Reference_8` FOREIGN KEY (`uid`) REFERENCES `user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
    ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Records of account
    -- ----------------------------
    INSERT INTO `account` VALUES (1, 46, 1000);
    INSERT INTO `account` VALUES (2, 45, 1000);
    INSERT INTO `account` VALUES (3, 46, 2000);
    
    SET FOREIGN_KEY_CHECKS = 1;
    
    insert  into `account`(`ID`,`UID`,`MONEY`) values (1,46,1000),(2,45,1000),(3,46,2000);
    
  2. 建立一个account的实体类

    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 +
                    '}';
        }
    }
    
  3. 创建一个account的dao接口IAccountDao

    package com.ben.dao;
    
    import com.ben.domain.Account;
    
    import java.util.List;
    
    /**
     * @ClassName: IAccountDao
     * @author: benjamin
     * @createTime: 2019/07/18/21:36
     */
    public interface IAccountDao {
    
        //查询所有
        List<Account> findAll();
    
    }
    
    
  4. 编写account配置文件

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <!--namespace:用来区别不同的类的名字 -->
    <mapper namespace="com.ben.dao.IAccountDao">
        <!--    查询所有-->
        <select id="findAll" resultType="com.ben.domain.Account">
            select * from account
        </select>
    </mapper>
    

    注意:一定要在SqlMapConfig.xml文件中配置别名:第一个是配置实体类中的别名;第二个是配置接口中类的别名。

    <!--使用typeAliases配置别名,它只能配置domain中类的别名 -->
    <typeAliases>
        <package name="com.ben.domain"></package>
    </typeAliases>
    
    <mappers>
        <package name="com.ben.dao"/>
    </mappers>
    
  5. 编写测试类

    //查询所有账户
    @Test
    public void testFindAll(){
        List<Account> list = accountDao.findAll();
        for (Account account : list) {
            System.out.println(account);
        }
    }
    

结果如下:

我们注意到,如果要用sql语句实现: 账户和用户的一对一关系。需要编写select * from account a, user u where u.id = a.uid;

再升级一下(查询的表里id有重复的部分):select u.*,a.id as aid,a.uid,a.money from account a, user u where u.id = a.uid;

思考:如何利用mybatis实现一对一查询的功能呢?

一对一

需求:

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

分析:

账户==》用户:一对一。因为一个账户信息只能供某个用户使用,所以从查询账户信息出发关联查询用户信息为一对一查询

用户==》账户:一对多。如果从用户信息出发查询用户下的账户信息则为一对多查询,因为一个用户可以有多个账户 。

方式一

使用 resultMap,定义专门的 resultMap 用于映射一对一查询结果。
通过面向对象的(has a)关系可以得知,我们可以在 Account 类中加入一个 User 类的对象来代表这个账户是哪个用户的。

  1. Account类修改: 在 Account 类中加入 User 类的对象作为 Account 类的一个属性

    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 +
                    '}';
        }
    }
    
  2. IAccountDao接口的修改

    注意:第二种方式,将返回值改 为了 Account 类型。因为 Account 类中包含了一个 User 类的对象,它可以封装账户所对应的用户信息。

    public interface IAccountDao {
        //查询所有,同时还有获取到当前账户的所属用户信息
        List<Account> findAll();
    }
    
  3. IAccountDao.xml配置文件的修改

  • 建立对应关系

  • 从指定从表方的引用实体属性

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.ben.dao.IAccountDao">
    
        <!-- 定义封装account和user的resultMap -->
        <resultMap id="accountUserMap" type="account">
            <id property="id" column="aid"></id>
            <result property="uid" column="uid"></result>
            <result property="money" column="money"></result>
            <!-- 一对一的关系映射:配置封装user的内容-->
            <association property="user" column="uid" javaType="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>
    </mapper>
    
  1. 编写测试方法

    //查询所有账户
    @Test
    public void testFindAll(){
        List<Account> list = accountDao.findAll();
        for (Account account : list) {
            System.out.println("--------每个account的信息------------");
            System.out.println(account);
            System.out.println(account.getUser());
        }
    }
    

方式二

  1. 定义账户信息的实体类

  2. 编写sql语句

    select u.*,a.id as aid,a.uid,a.money from user u , account a where u.id = a.uid
    
  3. 定义AccountUser类:

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

    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 + '\'' +
                    '}';
        }
    }
    
  4. 定义账户的Dao接口

    public interface IAccountDao {
    //    查询所有账户,并且带有用户名和地址信息
        List<AccountUser> findAllAccount();
    }
    
  5. 配置AccountDao.xml文件

    <!--查询所有账户同时包含用户名和地址信息-->
    <select id="findAllAccount" resultType="accountuser">
        select a.*,u.username,u.address from account a , user u where u.id = a.uid;
    </select>
    
  6. 创建测试类

    /**
     * 测试查询所有账户,同时包含用户名称和地址
     */
    @Test
    public void testFindAllAccountUser(){
        List<AccountUser> aus = accountDao.findAllAccount();
        for(AccountUser au : aus){
            System.out.println(au);
        }
    }
    ```![](https://img2018.cnblogs.com/blog/1415026/201907/1415026-20190720145849332-1587900413.png)
    

posted @ 2019-07-20 15:07  伊万夫斯基  阅读(415)  评论(0编辑  收藏  举报