Mybatis的延迟加载&&缓存
1. Mybatis中的延迟加载
延迟加载问题引入
问题:在一对多中,当我们有一个用户,他有100个账户。
1. 在查询用户的时候,要不要把关联的账户查询出来。
2. 在查询账户的时候,要不要把关联的用户查询出来。
答案:
1. 在查询用户的时候,用户下关联的账户信息应该是:什么时候使用,什么时候查询出来的。
2. 在查询账户的时候,账户下所属的用户信息应该是随着账户查询时一起查询出来的。
延迟加载和立即加载
1. 延迟加载:在真正使用数据的时候才发起查询,不使用的时候不查询。也叫按需加载、懒加载
2. 立即加载:不管用不用,只要一调用方法,马上发起查询。
什么时候使用延迟加载
问题:在四中表对应关系中:一对一、一对多、多对一、多对多那些需要使用延迟加载?
答案:
1. 一对多、多对多:通常情况下使用延迟加载(含有集合引用,如果不用延迟加载,浪费内存)
2. 一对一、多对一:通常情况下使用立即加载
Mybatis实现一对一延迟加载
public class Account implements Serializable {
private Integer ID;
private Integer UID;
private Double MONEY;
private User user;
. . .
}
要使用延迟加载,必须要先开启允许延迟加载【重点】【在主配置文件中配置如下】
< settings>
< setting name = " lazyLoadingEnabled" value = " true" />
< setting name = " aggressiveLazyLoading" value = " false" />
</ settings>
在IAccountDao.xml配置文件中配置如下:
<?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 = " itlearn.zhi.dao.IAccountDao" >
< resultMap id = " accountUser" type = " account" >
< id property = " ID" column = " ID" />
< result property = " UID" column = " UID" />
< result property = " MONEY" column = " MONEY" />
< association property = " user" column = " UID" javaType = " user"
select = " itlearn.zhi.dao.IUserDao.findUserById" fetchType = " lazy" > </ association>
</ resultMap>
< select id = " findAll" resultMap = " accountUser" >
select * from account;
</ select>
</ mapper>
@Test
public void testSelect ( ) throws IOException {
List< Account> accounts = dao. findAll ( ) ;
}
== > Preparing: select * from account;
== > Parameters:
== Total: 3
可见只有一条查询语句,并没有立即查询出账户指定的用户,即:实现了延迟加载
Mybatis实现一对多延迟加载
public class User implements Serializable {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
private List< Account> accounts;
. . .
}
<?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 = " itlearn.zhi.dao.IUserDao" >
< resultMap id = " userAccount" type = " user" >
< id property = " id" column = " id" > </ id>
< result property = " username" column = " username" > </ result>
< result property = " address" column = " address" > </ result>
< result property = " sex" column = " sex" > </ result>
< result property = " birthday" column = " birthday" > </ result>
< collection property = " accounts" ofType = " account" column = " id"
select = " itlearn.zhi.dao.IAccountDao.findAccountById" fetchtype = " lazy" > </ collection>
</ resultMap>
< select id = " findAll" resultMap = " userAccount" >
SELECT * FROM user;
</ select>
< select id = " findUserById" resultType = " user" parameterType = " Integer" >
SELECT * FROM user WHERE id = #{id};
</ select>
</ mapper>
延迟加载的本质:在使用的时候,去调用对方配置文件中的一个配置来实现查询
2. Mybatis中的缓存
缓存的概念:
1. 存在于内存中的临时数据
2. 在第一次查询数据库的结束后,将查询到的结果放到缓存中,当再次需要查询相同的数据的时候,只需要在缓存中获取,而不需要再从数据库中获取。
为什么使用缓存?
减少与数据库的交互次数,从而可以快速的把数据获取出来。提高执行效率。
什么样的数据可以使用缓存?什么样的数据不能使用缓存?
1. 什么样的数据可以使用缓存?
{
1. 经常查询,并且不经常改变
2. 数据的正确与否,对最终结果影响不大的。
}
2. 什么样的数据不能使用缓存?
{
1. 经常改变的数据。
2. 数据正确与否对最终结果影响很大的
例如:商品的库存、银行的汇率、股市的牌价
}
Mybatis中的一级缓存
一级缓存(SqlSession的缓存)
1. 一级缓存指的是mybatis中的SqlSession对象的缓存
2. 当我们执行查询之后,查询的结果会同时存入到SqlSession为我们提供的一块区域中。该区域的结构是一个Map,当我们再次查询同样的数据,mybatis中会先去Sqlsession中查看是否有数据,有的话直接拿出来,没有再去访问数据库。
3. 当SqlSession对象执行close方法之后,mybatis一级缓存也就消失了。
一级缓存的清空
1. 一级缓存是SqlSession范围的缓存,当调用SqlSession的修改,添加,删除,commit ( ) ,close ( ) ,clearCache ( ) 等方法时候,就会清空一级缓存。
案例:
1. 先执行了根据id查询方法: findByID ( 41 )
2. 执行更新操作, 对id为41 的记录进行更新: updateUser ( user)
3. 再次执行根据id查询方法:findByID ( 41 )
结果分析
1. 在执行完第一次根据id查询方法之后,查询到指定记录,存入SqlSession一级缓存。
2 ,在执行对id= 41 记录的更新操作之后,因为执行了SqlSession的update方法,导致原有的SqlSession一级缓存中的数据被清空。
3. 当再次执行根据id查询方法时,因为一级缓存被清空,所以直接向数据库中查询记录
4. 所以两次查询结果对象地址不相同
Mybatis中的二级缓存(SqlSessionFactory的缓存)
二级缓存:
1. mybatis中的二级缓存指的是SqlSessionFactory对象的缓存,由同一个SqlSessionFactory对象创建的SqlSession对象共享其缓存。
二级缓存的使用(三步)
1. 在SqlMapConfig.xml配置文件中配置开启二级缓存
< settings>
< setting name = " cacheEnabled" value = " true" />
</ settings>
2. 在dao层接口映射配置文件中配置开启支持二级缓存
< mapper namespace = " cn.zhi.dao.IUserDao" >
< cache/>
</ mapper>
3. 在对应的查询语句标签上调用二级缓存useCache="true"
< select id = " findUserByID" resultType = " User" parameterType = " java.lang.Integer" useCache = " true" >
SELECT * FROM user where id = #{id}
</ select>