前面一篇文章,介绍了多表查询,在实际使用中,咱们会常常性的涉及到多表联合查询,可是有时候,并不会当即用到全部的查询结果,我来举两个例子: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,而后再按照需求加载查询其余信息
若是文章中有什么不足,欢迎你们留言交流,感谢朋友们的支持!
若是能帮到你的话,那就来关注我吧!若是您更喜欢微信文章的阅读方式,能够关注个人公众号
在这里的咱们素不相识,却都在为了本身的梦而努力 ❤一个坚持推送原创开发技术文章的公众号:理想二旬不止