1. Mybatis中的延迟加载
1.1 问题
- 在一对多中,当一个用户有一百个账户,在查询用户的时候,要不要把关联的账户查询出来?在查询账户的时候,要不要将关联的用户查询出来?
1.2 解决
1 在查询用户时,用户下的账户信息应该是什么时候使用,什么时候查询的。(延迟加载)
- 在查询账户时,账户的所属用户信息应该是随着账户查询时一起查询出来。(立即加载)
1.3 概念
延迟加载 :在真正使用数据时才发起查询, 不用的时候不查询。也叫按需加载或懒加载。
立即加载:不管用不用,只要一旦调用方法,马上发起查询。
1.4 对应的四种表关系
一对多 ||多对多 :通常使用的是延迟加载;
多对一 || 一对一:通常使用的是立即加载;
2. 一对一实现延迟加载
2.1 创建一个新Demo
这里的Demo不使用骨架的方式创建,之后复制之前一对多Demo的代码。进行测试。
在查询账户的时查询用户信息,修改AccountDao.xml
<resultMap id="accountUserMap" type="account">
<!--此处使用懒加载数据库字段名称修改回来了 所以这里column = "id"-->
<id property="id" column="id"/>
<result property="uid" column="uid"/>
<result property="money" column="money"/>
<!--
一对一的关系映射:配置封装user的内容
property : 实体类中的类名
column : 关联的字段
javaType : 封装的类型
select : 指定需要查询的方法全限定类名 + 方法名称
-->
<association property="user" column="uid" javaType="user" select="com.lyp.dao.UserDao.findById">
</association>
</resultMap>
<!--使用关联查询-->
<select id="findAll" resultMap="accountUserMap">
select *
from account
</select>
- 在全局配置文件中配置懒加载:参考网址
<!--配置延迟加载-->
<settings>
<!--延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<!--按需加载-->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
注意事项这里的配置标签是有顺序的一定需要按照规定的顺序进行配置,否则将报错。
- 配置延迟加载之前 控制台日志信息:
3. 一对多实现延迟加载
- 在AccountDao.java持久层接口中添加根据用户id查询账户信息的方法。并在AccountDao.xml配置文件中进行配置:
/**
* 根据用户id查询账户信息
* @param uid
* @return
*/
List<Account> findAccountByUid(Integer uid);
<!--根据用户id查询账户户信息-->
<select id="findAccountByUid" resultType="account" parameterType="int">
select * from account where uid = #{uid}
</select>
- 在UserDao.xml中修改,用户和账户的关联映射:
<resultMap id="userAccountMap" type="user">
<id column="id" property="id"/>
<result property="username" column="username"/>
<result property="birthday" column="birthday"/>
<result property="sex" column="sex"/>
<result property="address" column="address"/>
<!--
property : 实体类中属性的名称
ofType : 集合中的类型
javaType: 返回值封装为什么类型
column : user 表需要根据哪个字段去查询 account表
-->
<collection property="accounts" ofType="account" select="com.lyp.dao.AccountDao.findAccountByUid" column="id">
</collection>
</resultMap>
- 使用延迟加载前后的区别:
3.1 Demo地址
- Demo地址 : 一对一 一对多 实现懒加载
4. Mybatis 缓存
4.1 什么是缓存?
- 缓存是存在内存中的临时数据。
4.2 为什么使用缓存?
- 减少和数据库交互次数,提高执行效率。
4.3 什么样的数据适用于缓存?
经常查询并且不经常改变的。
数据的正确与否对最终结果影响不大的。
4.4 不适用于使用缓存的?
- 经常改变的数据;
- 数据的正确性对最终结果影响很大的;
4.5 Mybatis的一级缓存
4.5.1 Mybatis的一级缓存简介
- Mybatis的一级缓存指的是Mybatis中SqlSession对象的缓存。当我们执行查询之后,查询结果会同时存入到SqlSession为我们提供的一块区域中。该区域的结构是一个Map。当我们再次查询同样的数据,Mbatis会先去SqlSession中查询是否有?有的话直接拿出来。
4.5.2 Mybatis中一级缓存Demo
创建一个普通的Maven工程,实现简单的查询所有User。
在findById方法中测试 :
- 未关闭SqlSession
/**
* 根据 id 查询用户信息
*/
@Test
public void findById() {
/*使用Mybatis SqlSession中的一级缓存进行测试*/
User user1 = userDao.findById(50);
System.out.println(user1);
User user2 = userDao.findById(50);
System.out.println(user2);
System.out.println(user1 == user2);
}
- 关闭SqlSession之后
/**
* 根据 id 查询用户信息
*/
@Test
public void findById() {
/*使用Mybatis SqlSession中的一级缓存进行测试*/
User user1 = userDao.findById(50);
System.out.println(user1);
// 在此处关闭SqlSession
session.close();
// 重新获取一个SqlSession
session = factory.openSession();
userDao = session.getMapper(UserDao.class);
User user2 = userDao.findById(50);
System.out.println(user2);
System.out.println(user1 == user2);
}
- 除了使用关闭SqlSession释放缓存的方式之外,还可以使用SqlSession的clearCache()方法释放缓存
/**
* 根据 id 查询用户信息
*/
@Test
public void findById() {
/*使用Mybatis SqlSession中的一级缓存进行测试*/
User user1 = userDao.findById(50);
System.out.println(user1);
/* // 在此处关闭SqlSession
session.close();
// 重新获取一个SqlSession
session = factory.openSession();*/
session.clearCache();
userDao = session.getMapper(UserDao.class);
User user2 = userDao.findById(50);
System.out.println(user2);
System.out.println(user1 == user2);
}
4.5.3 Mybatis中一级缓存如何做到同步
Mybatis的一级缓存,当调用SqlSession的修改、添加、删除、commit()、close()等方法就会清空一级缓存。
在UserDao持久层接口中添加一个更新用户信息的方法。进行测试。
/**
* 更新用户信息
* @param user
*/
void updateUser(User user);
<update id="updateUser" parameterType="user">
update user set username = #{username} , address = #{address}
where id = #{id}
</update>
- 编写测试类进行测试:
@Test
public void testUpdateToCache() {
User user1 = userDao.findById(41);
user1.setUsername("update to first level cache");
user1.setAddress("重庆市渝北区");
userDao.updateUser(user1);
System.out.println(user1);
// 再次查询
User user2 = userDao.findById(41);
System.out.println(user2);
System.out.println(user1 == user2);
}
4.6 Mybatis中的二级缓存
-
二级缓存概念:指的是Mybatis中SqlSessionFactory对象的缓存由同一个SqlSessiondFactory对象创建SqlSession共享其缓存。
4.6.1 二级缓存的使用步骤
- 让Mybatis框架支持二级缓存(在SqlMapConfig.xml中配置)。可以不用设置因为默认值就是true。
-
在让当前的映射配置文件支持缓存(在UserDao.xml中配置)。
让当前的操作支持二级缓存(在Select标签中配置)。
4.6.2 在测试类中编写测试类进行测试
/**
* 测试Mybatis的二级缓存 同一个factory创建的SqlSession对象共享缓存 但是前提是需要让Mybatis支持二级缓存
*/
@Test
public void testMyabtisSecondLevelCache() {
// 同一个factory创建的SqlSession对象共享缓存
SqlSession session1 = factory.openSession();
UserDao userDao1 = session1.getMapper(UserDao.class);
User user1 = userDao1.findById(41);
System.out.println(user1);
session1.close();
SqlSession session2 = factory.openSession();
UserDao userDao2 = session2.getMapper(UserDao.class);
User user2 = userDao2.findById(41);
System.out.println(user2);
session2.close();
System.out.println(user1 == user2);
}
4.6.2 Demo地址
- Demo地址 : Mybatis实现一级缓存和二级缓存