1. 程式人生 > 實用技巧 >【MyBatis】MyBatis 多表操作

【MyBatis】MyBatis 多表操作

MyBatis 多表操作

文章原始碼

一對一查詢

需求:查詢所有賬戶資訊,關聯查詢下單使用者資訊。

注意:因為一個賬戶資訊只能供某個使用者使用,所以從查詢賬戶資訊出發關聯查詢使用者資訊為一對一查詢。如果從使用者資訊出發關聯查詢使用者下的賬戶資訊則為一對多查詢,因為一個使用者可以有多個賬戶。

可以使用 resultMap,定義專門的 resultMap 用於對映一對一查詢結果。

  • 定義賬戶資訊的資料表

    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,41,1000),(2,45,1000),(3,41,2000);
    
  • 定義賬戶資訊的實體類

    package cn.parzulpan.domain;
    
    import java.io.Serializable;
    
    /**
    * @Author : parzulpan
    * @Time : 2020-12
    * @Desc :
    */
    
    public class Account implements Serializable {
        private Integer id;
        private Integer uid;
        private Double money;
        private 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;
        }
    
        public User getUser() {
            return user;
        }
    
        public void setUser(User user) {
            this.user = user;
        }
    
        @Override
        public String toString() {
            return "Account{" +
                    "id=" + id +
                    ", uid=" + uid +
                    ", money=" + money +
                    ", user=" + user +
                    '}';
        }
    }
    
  • 編寫 SQL

    select u.*, a.id as aid, a.uid, a.money
    from account a, user u
    where a.uid = u.id;
    
  • 定義賬戶的持久層 DAO 介面

    package cn.parzulpan.dao;
    
    import cn.parzulpan.domain.Account;
    
    import java.util.List;
    
    /**
    * @Author : parzulpan
    * @Time : 2020-12
    * @Desc :
    */
    
    public interface AccountDAO {
    
        /**
        * 查詢所有賬戶,同時獲取賬戶的所屬使用者名稱稱以及它的地址資訊
        * @return
        */
        List<Account> findAll();
    }
    
  • 配置 AccountDAO.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="cn.parzulpan.dao.AccountDAO">
    
        <!-- 建立對應關係 -->
        <resultMap id="accountMap" type="account">
            <id column="aid" property="id"/>
            <result column="uid" property="uid"/>
            <result column="money" property="money"/>
    
            <!-- 用於指定從資料表方的引用實體屬性 -->
            <association property="user" javaType="user">
                <id column="id" property="id"/>
                <result column="username" property="username"/>
                <result column="sex" property="sex"/>
                <result column="birthday" property="birthday"/>
                <result column="address" property="address"/>
            </association>
        </resultMap>
    
        <select id="findAll" resultMap="accountMap">
            select u.*, a.id as aid, a.uid, a.money
            from account a, user u
            where a.uid = u.id;
        </select>
    </mapper>
    
  • 測試

    package cn.parzulpan.test;
    
    import cn.parzulpan.dao.AccountDAO;
    import cn.parzulpan.domain.Account;
    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.IOException;
    import java.io.InputStream;
    import java.util.List;
    
    /**
    * @Author : parzulpan
    * @Time : 2020-12
    * @Desc : 多表查詢
    */
    
    public class MyBatisQueryTest {
        private InputStream is;
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        private SqlSessionFactory factory;
        private SqlSession session;
        private AccountDAO accountDAO;
    
        @Before
        public void init() throws IOException {
            is = Resources.getResourceAsStream("SqlMapConfig.xml");
            factory = builder.build(is);
            session = factory.openSession();
            accountDAO = session.getMapper(AccountDAO.class);
        }
    
        @After
        public void destroy() throws IOException {
            session.commit();   // 事務提交
            session.close();
            is.close();
        }
    
        @Test
        public void findAllTest() {
            List<Account> accounts = accountDAO.findAll();
            for (Account account : accounts) {
                System.out.println(account);
                System.out.println(account.getUser());
            }
        }
    }
    
    

一對多查詢

需求:查詢所有使用者資訊及使用者關聯的賬戶資訊。

分析:使用者資訊和他的賬戶資訊為一對多關係,並且查詢過程中如果使用者沒有賬戶資訊,此時也要將使用者資訊查詢出來,所以左外連線查詢比較合適。

  • 編寫 SQL

    select u.*, a.id as id, a.uid, a.money
    from user u left join account a on u.id = a. uid;
    
  • User 類加入 List<Account>

  • 使用者持久層 DAO 介面中加入查詢方法

    /**
    * 查詢所有使用者,同時獲取出每個使用者下的所有賬戶資訊
    * @return
    */
    List<User> findAllAndAccount();
    
  • 配置 UserDAO.xml 檔案

        <resultMap id="userMap" type="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 是用於建立一對多中集合屬性的對應關係 ofType 用於指定集合元素的資料型別 -->
            <collection property="accounts" ofType="account">
                <id column="aid" property="id"/>
                <result column="uid" property="uid"/>
                <result column="money" property="money"/>
            </collection>
        </resultMap>
    
        <select id="findAllAndAccount" resultMap="userMap">
            select u.*, a.id as aid, a.uid, a.money
            from user u left join account a on u.id = a. uid;
        </select>
    
  • 測試

    @Test
    public void findAllAndAccountTest() {
        List<User> users = userDAO.findAllAndAccount();
        for (User user : users) {
            System.out.println();
            System.out.println("----- " + user.getUsername() + " -----");
            System.out.println(user);
            System.out.println(user.getAccounts());
        }
    }
    

多對多查詢

需求:實現查詢所有物件並且載入它所分配的使用者資訊。

注意:查詢角色我們需要用到Role表,但角色分配的使用者的資訊我們並不能直接找到使用者資訊,而是要通過中間表(USER_ROLE 表)才能關聯到使用者資訊。

  • 定義相關的資料表

    # -----
    
    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);
    
  • 定義角色資訊的實體類

    package cn.parzulpan.domain;
    
    import java.io.Serializable;
    import java.util.List;
    
    /**
    * @Author : parzulpan
    * @Time : 2020-12
    * @Desc : 角色實體類
    */
    
    public class Role implements Serializable {
        private Integer roleId;
        private String roleName;
        private String roleDesc;
    
        private List<User> 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;
        }
    
        public List<User> getUsers() {
            return users;
        }
    
        public void setUsers(List<User> users) {
            this.users = users;
        }
    
        @Override
        public String toString() {
            return "Role{" +
                    "roleId=" + roleId +
                    ", roleName='" + roleName + '\'' +
                    ", roleDesc='" + roleDesc + '\'' +
                    ", users=" + users +
                    '}';
        }
    }
    
  • 編寫 RoleDAO 持久層介面

    package cn.parzulpan.dao;
    
    import cn.parzulpan.domain.Role;
    
    import java.util.List;
    
    /**
    * @Author : parzulpan
    * @Time : 2020-12
    * @Desc :
    */
    
    public interface RoleDAO {
    
        /**
        * 查詢所有角色
        * @return
        */
        List<Role> findAll();
    }
    
    
  • 編寫對映檔案

    <?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="cn.parzulpan.dao.RoleDAO">
    
        <!-- 建立對應關係 -->
        <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 r.id as rid, r.role_name, r.role_desc, u.*
            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>
    </mapper>
    
  • 測試

    package cn.parzulpan.test;
    
    import cn.parzulpan.dao.AccountDAO;
    import cn.parzulpan.dao.RoleDAO;
    import cn.parzulpan.domain.Account;
    import cn.parzulpan.domain.Role;
    import cn.parzulpan.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.IOException;
    import java.io.InputStream;
    import java.util.List;
    
    /**
    * @Author : parzulpan
    * @Time : 2020-12
    * @Desc : 多表查詢
    */
    
    public class MyBatisManyQueryTest {
        private InputStream is;
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        private SqlSessionFactory factory;
        private SqlSession session;
        private RoleDAO roleDAO;
    
        @Before
        public void init() throws IOException {
            is = Resources.getResourceAsStream("SqlMapConfig.xml");
            factory = builder.build(is);
            session = factory.openSession();
            roleDAO = session.getMapper(RoleDAO.class);
        }
    
        @After
        public void destroy() throws IOException {
            session.commit();   // 事務提交
            session.close();
            is.close();
        }
    
        @Test
        public void findAllTest() {
            List<Role> roles = roleDAO.findAll();
            for (Role role : roles) {
                System.out.println();
                System.out.println("----- " +  " -----");
                System.out.println(role);
                if (role != null) {
                    System.out.println(role.getUsers());
                }
            }
        }
    }
    

練習和總結