通過了 MyBatis 基本增刪改查的學習,而在實際的項目中,咱們每每會接觸到多表的操做,什麼是多表呢, 在實際生活中,每一個實體之間每每是存在關係的,而咱們的項目倒是要依賴數據庫將這些實體之間的關係串聯起來,從而實現咱們的業務,因此這部分,咱們着重講解如何使用 MyBatis 框架處理多張數據表之間的聯繫,幫助咱們更加理解數據庫的映射關係java
用戶和訂單/理財產品sql
部門和員工數據庫
訂單和用戶微信
學生選課和學生mybatis
身份證、護照等證件app
能夠看到,第二章內容咱們直接進入了業務表的內容,而因爲前幾篇文章的鋪墊,我將User的相關信息都沒有講解,缺失的內容只有用戶實體類,以及對應 XML 映射文件,這個很是簡單 以及對應測試類框架
文章中咱們使用用戶和帳戶之間的帳戶的關係,即:ide
首先須要創建兩張表:用戶表和帳戶表學習
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;
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); } }
看一下效果:
如何查詢到 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;
這樣看起來就條理了許多
到了這一步,咱們就能夠在代碼中實現這樣的功能了,即經過查詢帳戶信息,同時查詢出對應的用戶信息,那因爲註冊時間,男女等信息,我並不想要,怎麼辦呢?咱們能夠再加一點約束,用戶的信息只顯示名稱和地址兩個字段
/** * 查詢全部帳戶,而且帶有用戶名稱和地址信息 * @return */ List<UserAccount> findAllAccount();
你們可能注意到咱們返回的 List 類型爲 UserAccount,這是爲何呢?
既然咱們想返回的信息中,須要包含兩個表中的信息,彷佛咱們並無一個實體能夠承載這麼多信息,因此咱們建立一個 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 能夠方便咱們調用輸出查詢到帳戶中的信息
<select id="findAllAccount" resultType="UserAccount"> select a.*,u.username,u.address from account a , user u where u.id = a.uid; </select>
/** * 查詢全部帳戶,而且帶有用戶名稱和地址信息 * @return */ @Test public void testFindAllAccount(){ List<UserAccount> uas = accountMapper.findAllAccount(); for (UserAccount ua : uas ){ System.out.println(ua); } }
/** * 查詢全部帳戶 * @return */ List<Account> findAll();
在 Account 類中須要增長一個User對象的引用,這也就是對應着咱們的 user 主表
//從表實體應該包含一個主表實體的對象引用 private User user; public User getUser() { return user; } public void setUser(User user) { this.user = user; }
<!-- 定義封裝 Account和User 的resultMap --> <resultMap id="userAccountMap" 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 property="username" column="username"></result> <result property="telephone" column="telephone"></result> <result property="birthday" column="birthday"></result> <result property="gender" column="gender"></result> <result property="address" column="address"></result> </association> </resultMap> <!-- 根據查詢全部用戶 --> <select id="findAll" resultMap="userAccountMap"> SELECT u.*,a.id AS aid,a.uid,a.money FROM account a,user u WHERE u.id = a.uid; </select>
說明:因爲咱們想要返回的結果爲多個值,是沒有一個徹底與返回結果值一一匹配的封裝類去接收的,因此咱們可使用MyBatis 提供的 resultMap 進行接收結果數據,它會在列名和 Java 包裝類屬性名之間建立映射關係,這篇文章的重心仍是放在表的操做上,關於這個問題,之後能夠專門寫篇文章進行說明,若是對這部分不清楚的朋友,能夠本身查一下這些標籤的意義,實際上不會太過於複雜的
/** * 測試查詢全部 */ @Test public void testFindAll(){ List<Account> accounts = accountMapper.findAll(); for (Account account : accounts){ System.out.println("--------------------------"); System.out.println(account); System.out.println(account.getUser()); } }
/** * 查詢全部用戶信息,同時顯示出該用戶下的全部帳戶 * * @return */ List<User> findAll();
在 Java 類中應該添加一個集合成員,類型爲 Account,方便咱們承載帳戶的信息
//一對多關係映射,主表實體應該包含從表實體的集合引用 private List<Account> accounts; public List<Account> getAccounts() { return accounts; } public void setAccounts(List<Account> accounts) { this.accounts = accounts; }
<!-- 定義User的resultMap--> <resultMap id="userAccountMap" type="User"> <id property="id" column="id"></id> <result property="username" column="username"></result> <result property="telephone" column="telephone"></result> <result property="birthday" column="birthday"></result> <result property="gender" column="gender"></result> <result property="address" column="address"></result> <collection property="accounts" ofType="account"> <id property="id" column="aid"></id> <result property="uid" column="uid"></result> <result property="money" column="money"></result> </collection> </resultMap> <!-- 根據查詢全部用戶 --> <select id="findAll" resultMap="userAccountMap"> SELECT * FROM user u LEFT OUTER JOIN account a on u.id = a.uid; </select>
注:LEFT OUTER JOIN
:左外鏈接,能夠將左表的數據所有顯示出來
/** * 測試查詢全部 */ @Test public void testFindAll() { List<User> users= userMapper.findAll(); for (User user : users) { System.out.println("--------------------------"); System.out.println(user); System.out.println(user.getAccounts()); } }
能夠看到,全部用戶信息被打印了出來(上圖只截取了前面的部分),而且在用戶下存在全部帳戶的信息也被打印了出來
前面咱們看完了,用戶以及帳戶之間一對多的關係,下面咱們來研究一下多對多的狀況,這種,狀況會麻煩一些,例如咱們舉個例子:用戶以及職位之間的關係
可是如何將兩個錶鏈接起來呢?這就須要一箇中間表,用來使得兩個表之間產生關係
首先建立一個職位表
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,'校長','管理整個學校');
接着咱們建立中間表
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 (12,1),(16,1),(12,2);
至於用戶表,咱們依舊沿用前面的 user 的一套
public class Role implements Serializable { private Integer roleId; private String roleName; private String roleDesc; ...... 省略對應 get set toString 方法 }
public interface RoleMapper { /** * 查詢全部職位 * @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.ideal.mapper.RoleMapper"> <!-- 定義Role的resultMap--> <resultMap id="roleMap" type="Role"> <id property="roleId" column="id"></id> <result property="roleName" column="role_name"></result> <result property="roleDesc" column="role_desc"></result> </resultMap> <!-- 根據查詢全部用戶 --> <select id="findAll" resultMap="roleMap"> SELECT * FROM role </select> </mapper>
須要特別注意的是:column中的值是數據庫中字段名,而property中的值是JavaBean中的對應成員變量,因爲二者的名字並非相同的,因此請注意區分
@Test public void testFindAll(){ List<Role> roles = roleMapper.findAll(); for (Role role : roles){ System.out.println("-----------------------"); System.out.println(role); } }
在 Role 實體類中增長 User 類型的 List集合
//多對多關係映射,一個職位能夠擁有多個用戶 private List<User> users; public List<User> getUsers() { return users; } public void setUsers(List<User> users) { this.users = users; }
接口方法咱們仍然用前面建立的,findAll 方法
在這部分,毫無疑問,須要建立 Role 的 resultMap ,還要一部分,就是對應 SQL 語句的編寫
SQL語句的編寫咱們須要簡單的分析一下,首先看一下,三張表之間的關係
中間表經過UID RID兩個字段分別鏈接起了 user 和 role 兩張表
先經過 role 表中的 id 找到 中間表的 rid 而後經過 rid 對應的 uid值 找到 user 表中的 id 值,從而獲取到對應的用戶信息
這個時候咱們須要兩個左外鏈接,xml 代碼以下
<mapper namespace="cn.ideal.mapper.RoleMapper"> <!-- 定義Role的resultMap--> <resultMap id="roleMap" type="Role"> <id property="roleId" column="rid"></id> <result property="roleName" column="role_name"></result> <result property="roleDesc" column="role_desc"></result> <collection property="users" ofType="User"> <id property="id" column="id"></id> <result property="username" column="username"></result> <result property="telephone" column="telephone"></result> <result property="birthday" column="birthday"></result> <result property="gender" column="gender"></result> <result property="address" column="address"></result> </collection> </resultMap> <!-- 根據查詢全部用戶 --> <select id="findAll" resultMap="roleMap"> SELECT u.*,r.id AS rid,r.role_name,r.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> </mapper>
@Test public void testFindAll(){ List<Role> roles = roleMapper.findAll(); for (Role role : roles){ System.out.println("---------------------"); System.out.println(role); System.out.println(role.getUsers()); } }
public interface UserMapper { /** * 查詢全部用戶信息,同時顯示出該用戶下的全部帳戶 * * @return */ List<User> findAll(); }
這是多對多的關係映射,一個用戶能夠具有多個角色
private List<Role> roles; public List<Role> getRoles() { return roles; } public void setRoles(List<Role> roles) { this.roles = roles; }
<mapper namespace="cn.ideal.mapper.RoleMapper"> <!-- 定義Role的resultMap--> <resultMap id="roleMap" type="Role"> <id property="roleId" column="rid"></id> <result property="roleName" column="role_name"></result> <result property="roleDesc" column="role_desc"></result> <collection property="users" ofType="User"> <id property="id" column="id"></id> <result property="username" column="username"></result> <result property="telephone" column="telephone"></result> <result property="birthday" column="birthday"></result> <result property="gender" column="gender"></result> <result property="address" column="address"></result> </collection> </resultMap> <!-- 根據查詢全部用戶 --> <select id="findAll" resultMap="roleMap"> SELECT u.*,r.id AS rid,r.role_name,r.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> </mapper>
@Test public void testFindAll(){ List<User> users = userMapper.findAll(); for (User user : users){ System.out.println("---------------------"); System.out.println(user); System.out.println(user.getRoles()); } }
若是文章中有什麼不足,歡迎你們留言交流,感謝朋友們的支持!
若是能幫到你的話,那就來關注我吧!若是您更喜歡微信文章的閱讀方式,能夠關注個人公衆號
在這裏的咱們素不相識,卻都在爲了本身的夢而努力 ❤一個堅持推送原創開發技術文章的公衆號:理想二旬不止