一、延迟加载策略
1. 延迟加载的概念
在MyBatis中也称为懒加载,是指在进行表的关联查询时,不立即加载关联的对象,而是在真正使用到关联对象的数据时才执行查询。这种机制有助于提高应用程序的性能,尤其是在处理一对多或多对多关系时,可以避免不必要的查询,从而减少数据库的压力和内存的使用。
- 立即加载和延迟加载的区别,使用一对多的环境举例子。
- 立即加载:当前查询用户的时候,默认也把该用户所拥有的帐户信息查询出来了。
- 延迟加载:当前查询用户的时候,没有把该用户所拥有的帐户信息查询出来,而是使用帐户数据的时候,再去查询账户的数据。
2. 立即加载和延迟加载的应用场景
- 例如查询账户的时候,可以直接把用户查询出来,即查询多对一,这个时候可以选择立即加载。
- 例如查询用户的时候,可以先不查账号信息,等需要使用帐户信息的时候,再去查询,选择延迟加载。
3.举例
编写accountmapper
<!-- 内连接的查询 -->
<select id="findAll" resultMap="accountMap">
SELECT * from account
</select>
<!-- 通过用户的id查询账户信息 -->
<select id="findByUid" parameterType="int" resultType="account">
select * from account where uid = #{uid}
</select>
<!-- 配置映射 -->
<resultMap type="Account" id="accountMap">
<id column="id" property="id"/>
<result column="uid" property="uid"/>
<result column="money" property="money"/>
<!-- 配置延迟加载 -->
<association property="user" javaType="User" select="com.qcbyjy.mapper.UserMapper.findById" column="uid">
<id column="id" property="id"/>
<result column="username" property="username"/>
<result column="birthday" property="birthday"/>
<result column="sex" property="sex"/>
<result column="addresss" property="addresss"/>
</association>
</resultMap>
UserMapper
<select id="findById" parameterType="int" resultType="User">
select * from user where id = #{id}
</select>
修改配置
<settings>
<!-- 开启延迟加载 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 将积极加载改为消极加载及按需加载 -->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
测试
@Test
public void testFindAll() throws Exception {
// 调用方法
List<Account> list = mapper.findAll();
for (Account account : list) {
System.out.println("开始...");
System.out.println(account.getMoney());
System.out.println("结束...");
System.out.println();
}
}
4、一对多举例
usermapper
<!-- 一对多的查询 -->
<select id="findAll" resultMap="userMap">
select * from user
</select>
<!-- 数据封装 -->
<resultMap type="user" id="userMap">
<id column="id" property="id"/>
<result column="username" property="username"/>
<result column="birthday" property="birthday"/>
<result column="sex" property="sex"/>
<result column="addresss" property="addresss"/>
<!--
select="" 使用帐户的方法查询
column="id" 使用id值去查询账户
-->
<collection property="accounts" ofType="Account" select="com.qcbyjy.mapper.AccountMapper.findByUid" column="id" >
<id column="id" property="id"/>
<result column="uid" property="uid"/>
<result column="money" property="money"/>
</collection>
</resultMap>
accountmapper
<!-- 通过用户的id查询账户信息 -->
<select id="findByUid" parameterType="int" resultType="account">
select * from account where uid = #{uid}
</select>
开启延时加载
<settings>
<!-- 开启延迟加载 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 将积极加载改为消极加载及按需加载 -->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
测试
@Test
public void testFindAll() throws Exception {
// 调用方法
List<User> list = mapper.findAll();
for (User user : list) {
System.out.println(user.getUsername());
System.out.println(user.getAccounts());
System.out.println("==============");
}
}
二、缓存
缓存的概念
-
缓存的概念
- 在内存中临时存储数据,速度快,可以减少数据库的访问次数。
- 经常需要查询,不经常修改的数据,不是特别重要的数据都适合于存储到缓存中。
-
缓存可以将数据保存在内存中,是互联网系统常常用到的。目前流行的缓存服务器有 MongoDB、Redis、Ehcache 等。缓存是在计算机内存上保存的数据,读取时无需再从磁盘读入,因此具备快速读取和使用的特点。
和大多数持久化框架一样,MyBatis 提供了一级缓存和二级缓存的支持。默认情况下,MyBatis 只开启一级缓存。
MyBatis的一级缓存
MyBatis的一级缓存也是SqlSession的缓存。
SqlSession对象中维护了一个Map集合,用于存储相互的缓存数据。
查询的时候,先从SqlSession的缓存中查找,如果有,直接返回。如果没有,查询数据库。
证明一级缓存的存在,通过用户id查询2次,查看结果。
/**
* 测试一级缓存是否存在
*/
@Test
public void testFindById() {
User user = mapper.findById(41);
System.out.println(user);
User user2 = mapper.findById(41);
System.out.println(user2);
}
-
一级缓存的原理分析
-
一级缓存底层使用的是Map集合,key存储的是执行的SQL语句,value存放的是查询的对象
-
BaseExecutor类的152行源码地方先查询缓存,再查询数据库。
-
一级缓存的生命周期和SqlSession的生命周期相同,SqlSession对象关闭,一级缓存也会关闭。
- session.clearCache();调用该方法可以清空缓存
- 调用调用SqlSession的update、insert、delete、commit和close等方法的时候也会清空缓存。
-
二级缓存
MyBatis 的二级缓存是一个跨 SqlSession 的共享缓存,它的作用范围是 namespace 级别的,可以被多个 SqlSession 共享。这意味着,只要是同一个接口里面的相同方法,都可以共享这个缓存。二级缓存的生命周期与应用同步,当 MyBatis 使用了二级缓存,并且相应的 Mapper 和 select 语句也配置使用了二级缓存,那么在执行 select 查询时,MyBatis 会先从二级缓存中取数据,其次才是一级缓存,最后才是数据库