前面一篇文章,介紹了多表查詢,在實際使用中,咱們會常常性的涉及到多表聯合查詢,可是有時候,並不會當即用到全部的查詢結果,我來舉兩個例子:java
針對這樣一種狀況,延遲加載這一種機制就出現了,延遲加載(懶加載)顧名思義,就是對某種信息推遲加載,這樣的技術也就幫助咱們實現了 「按需查詢」 的機制,在一對多,或者多對多的狀況下sql
既然提到了延遲加載,固然順便提一句當即加載,它的含義就是不論是否用戶須要,一調用,則立刻查詢,這種方式,適合與多對一,或者一對一的狀況下數據庫
首先,配置基本的環境,而後咱們首先在數據庫準備兩張表微信
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;
而後分別建立出其對應的實體類mybatis
public class User implements Serializable { private Integer id; private String username; private String telephone; private Date birthday; private String gender; private String address; //一對多關係映射,主表實體應該包含從表實體的集合引用 private List<Account> accounts; ...... 請補充 get set 和 toString 方法 }
public class Account implements Serializable { private Integer id; private Integer uid; private Double money; //從表實體應該包含一個主表實體的對象引用 private User user; ...... 請補充 get set 和 toString 方法 }
<?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.UserMapper"> <!-- 定義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 u.*,a.id as aid,a.uid,a.money FROM user u LEFT OUTER JOIN account a on u.id = a.uid; </select> <!-- 根據id查詢用戶 --> <select id="findById" parameterType="INT" resultType="User"> select * from user where id = #{uid} </select> </mapper>
public interface AccountMapper { /** * 查詢全部帳戶 * @return */ List<Account> findAll(); }
public interface UserMapper { /** * 查詢全部用戶信息,同時顯示出該用戶下的全部帳戶 * * @return */ List<User> findAll(); /** * 根據id查詢用戶信息 * @param userId * @return */ User findById(Integer userId); }
首先,給你們演示一下,咱們以前一對一查詢用戶的方式,同時會將用戶對應全部的帳戶信息,也查詢出來app
/** * 測試查詢全部 */ @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()); } }
效果:ide
這種方式是經過 SQL 語句,以及resultMap將 用戶和帳戶的信息同時查詢出來測試
那麼如何實現咱們上面所說的延遲加載呢?ui
此次咱們選擇 查詢帳戶,而後延遲加載用戶的信息idea
首先須要修改的就是帳戶的映射配置文件,能夠看到咱們在查詢時,依舊定義了一個 resultMap 先封裝了 Account ,而後經過association 進行關聯 User,其中使用的就是 select 和 column 實現了延遲加載用戶信息
<mapper namespace="cn.ideal.mapper.AccountMapper"> <!-- 定義封裝 Account和User 的resultMap --> <resultMap id="userAccountMap" type="Account"> <id property="id" column="id"></id> <result property="uid" column="uid"></result> <result property="money" column="money"></result> <!-- 配置封裝 User 的內容 select:查詢用戶的惟一標識 column:用戶根據id查詢的時候,須要的參數值 --> <association property="user" column="uid" javaType="User" select="cn.ideal.mapper.UserMapper.findById"></association> </resultMap> <!-- 根據查詢全部帳戶 --> <select id="findAll" resultMap="userAccountMap"> SELECT * FROM account </select> </mapper>
咱們只執行一下帳戶的查詢全部方法,看一下,是否可以實現咱們的效果
@Test public void testFindAll(){ List<Account> accounts = accountMapper.findAll(); }
能夠看到,三條 SQL 語句都執行了,這是爲何呢?
這是由於,咱們在測試方法以前,須要開啓延遲加載功能
咱們能夠去官網,如何配置開啓這樣一個功能
通過查閱文檔,咱們知道了,若是想要開始延遲加載功能,就須要在總配置文件 SqlMapConfig.xml 中配置 setting 屬性,也就是將延遲加載 lazyLoadingEnable
的開關設置成 teue ,因爲是按需加載,因此還須要將積極加載修改成消極加載,也就是將 aggressiveLazyLoading
改成 false
固然,因爲我這裏導入的 MyBatis 版本爲 3.4.5 因此這個值默認就是 false 實際上不用設置也能夠,不過咱們仍是寫出來
<settings> <setting name="lazyLoadingEnabled" value="true"/> <setting name="aggressiveLazyLoading" value="false"></setting> </settings>
注意:若是有使用typeAliases配置別名的話必定要將 typeAliases 標籤放在後面
仍然只執行查詢方法
@Test public void testFindAll(){ List<Account> accounts = accountMapper.findAll(); }
執行效果
這一次果真只執行了一條查詢 account 的命令
那麼當用戶想要查看到,每一個帳戶對應下的用戶的時候呢?這也就是按需查詢,只須要在測試時,加入對應獲取方法就能夠了
@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()); } }
執行一下
能夠看到,咱們延遲加載的目的達到了
上面的測試,咱們已經實現了延遲加載,簡單的總結一下步驟:
②:在程序中,遍歷查詢到的 accounts ,調用 getUser() 方法時,開始進行延遲加載
List<Account> accounts = accountMapper.findAll();
能夠看到,咱們以前經過使用 左外鏈接等的 SQL書寫方式,直接就能夠查詢到多張表
SELECT u.*,a.id as aid,a.uid,a.money FROM user u LEFT OUTER JOIN account a on u.id = a.uid;
可是咱們能夠經過延遲加載,實現咱們按需查詢的需求,綜上所述,在使用的時候,先執行簡單的 SQL,而後再按照需求加載查詢其餘信息
若是文章中有什麼不足,歡迎你們留言交流,感謝朋友們的支持!
若是能幫到你的話,那就來關注我吧!若是您更喜歡微信文章的閱讀方式,能夠關注個人公衆號
在這裏的咱們素不相識,卻都在爲了本身的夢而努力 ❤一個堅持推送原創開發技術文章的公衆號:理想二旬不止