我们已经掌握了 Mybatis 中一对一,一对多,多对多关系的配置及实现,可以实现对象的关联查询。实际开发过程中很多时候我们并不需要总是在加载用户信息时就一定要加载他的账户信息。此时就是我们所说的延迟加载。
什么是延迟加载?
就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载;
好处:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速
度要快
坏处:因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降。
实现需求
需求:
查询账户(Account)信息并且关联查询用户(User)信息。如果先查询账户(Account)信息即可满足要求,当我们需要查询用户(User)信息时再查询用户(User)信息。把对用户(User)信息的按需去查询就是延迟加载。
mybatis实现多表操作时,我们使用了resultMap来实现一对一,一对多,多对多关系的操作。主要是通过 association、collection 实现一对一及一对多映射。association
、collection
具备延迟加载功
能。
Mybaits 延迟加载
实现查询Account的时候不查询User,而是在要使用User的时候才去查询
使用了lombook依赖,简化getter/setter
一、 使用association 实现延迟加载
Account
@Data
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money;
//放入了User
private User user;
}
User
@Data
public class User implements Serializable {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
}
public interface AccountMapper {
/**
* 查询所有账户,以及账户所属用户名称和地址信息
* @return
*/
List<Account> findAll();
}
<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"
select="com.it.mapper.UserMapper.findById"
column="uid"
>
</association>
</resultMap>
<select id="findAll" resultMap="accountMap">
select * from account
</select>
select
会在加载的时候去调用这个UserMapper中的方法,传入的参数就是 Account中的uid
配置懒加载,在SqlMapperConfig.xml中配置
<settings>
<!--开启懒加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
lazyLoadingEnabled
开启Mybatis支持延迟加载
aggressiveLazyLoading
触发方法立即加载
测试懒加载
//测试account user 的懒加载
@Test
public void testLazyLoadUser(){
List<Account> accounts = accountMapper.findAll();
}
执行日志
可以看到只查询了account中的所有信息,并没有去查询user中的信息
这是因为我们在测试的时候,只是执行了查询语句,没有使用查询结果,修改测试方法,打印输出account的内容
//测试account user 的懒加载
@Test
public void testLazyLoadUser(){
List<Account> accounts = accountMapper.findAll();
for(Account account : accounts){
System.out.println(account);
}
}
执行sql过程,可以看到,account中用三条记录,通过account中与user的关联id去查询了user,
为什么只查询了两个呢? 这是因为account中的数据有两条的userid是相同的。
image.png
二、使用Collection实现延迟加载
同样我们也可以在一对多关系配置的<collection>
结点中配置延迟加载策略。
<collection>
结点中也有 select 属性,column 属性。
需求:完成加载用户对象时,查询该用户所拥有的账户信息。
修改User中的内容,注意要把Account中的user去除
@Data
public class User implements Serializable {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
private List<Account> accounts;
}
思路,先查询user表,根据懒加载策略,通过user的id去查询account表
因此要在account的mapper中添加一个根据userid查询account的接口
List <Account> fingByUid(Integer uid);
<select id="fingByUid" resultType="Account" parameterType="int">
select * from account where uid = #{uid}
</select>
在user的mappper接口中添加方法
List<User> findAll();
UserMapper.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 property="accounts" ofType="Account"
select="com.it.mapper.AccountMapper.findByUid"
column="id"
>
</collection>
</resultMap>
<select id="findAll" resultMap="userMap">
select * from user
</select>
属性解读:
collection
标签 :主要用于加载关联的集合对象
select
属性 :用于指定查询 account 列表的 sql 语句,指定account中的接口 ,所以填写的是该 sql 映射的 id
column
属性 :用于指定 select 属性的 sql 语句的参数来源,上面的参数来自于 user 的 id 列,所以就写成 id 这一
个字段名了
测试
@Test
public void testFindAll(){
List<User> all = userMapper.findAll();
}
image.png
可以看到同样只查询了user
输出user
@Test
public void testFindAll(){
List<User> all = userMapper.findAll();
for(User user:all){
System.out.println(user);
}
}
image.png
网友评论