文章目录
- 1、MyBatis执行流程
- 2、MyBatis延迟加载使用
- 3、MyBatis延迟加载的原理
- 4、MyBatis的一级、二级缓存
- 4.1 一级缓存
- 4.2 二级缓存
- 4.3 注意点
- 5、面试
1、MyBatis执行流程
- 从mybatis-config.xml读取配置(数据库连接信息,xml映射文件)
- 构建会话工厂SqlSessionFactory,会话工厂,全局一个
- SqlSessionFactory负责生产SqlSession,SqlSession包含执行SQL语句的所有方法
- Executor执行器去操作数据库,其API方法有一个MappedStatement类型的参数,该类型的对象封装了SQL映射信息
- Debug下MappedStatement对象,其属性值中,有SQL、Mapper层方法名称、结果集等信息,当时AOP采集数据库执行信息,SQL便来源于此对象
流程:
2、MyBatis延迟加载使用
用户表和订单表一对多的关系,一个用户有多个订单。实体类:
Mapper.xml这么写:
此时,调用selectById:
发现其执行了两句SQL:
MyBatis延迟加载,即查询用户时,暂时不要去查询订单数据。当调用了user.getOrderList时,再去执行查订单的SQL。反之,一次都查出来,是立即加载。开启延迟加载,可加fetchType="lazy"
,开启局部延迟加载:
此时,再执行:
执行user.getOrderList时,才会执行查订单的SQL,注释调user.getOrderList,查订单的SQL直接不会去执行。最后,开启全局延迟加载可以修改MyBatis配置:
3、MyBatis延迟加载的原理
- 使用动态代理,创建目标对象User的代理对象
- 调用user.getOrderList方法时,进入代理对象的intercept方法(或revoke方法)
- intercept方法(或revoke方法),做判断,如果user.getOrderList是null值,就执行sql查询订单列表
- 查询完成后,调用user.setOrderList,封装订单信息到User的Order属性
- 正常调用真实对象中的方法的Method实例,即user.getOrderList
最后,MyBatis使用哪种动态代理,取决于被代理的对象是否实现了接口(因为JDK动态代理有使用局限):
4、MyBatis的一级、二级缓存
MyBatis的一级、二级缓存,都是基于PerpetualCache,本质是一个HashMap。但二者作用域不同:
- 一级缓存:生效的范围是session级别
- 二级缓存:生效范围和session无关,作用域是namespace和mapper
4.1 一级缓存
- session级别,当Session进行flush或者close,该session里的所有缓存数据就会被全部清空
- 默认开启
4.2 二级缓存
- 基于namespace和mapper作用域,和SQLSession无关
- 默认关闭状态
如下,两个SqlSession对象操作数据库,会查询两次,因为二级缓存默认关闭:
打开二级缓存:
- 修改全局配置文件
- 使用
<cache/>
标签让当前mapper生效二级缓存
4.3 注意点
- 当某一个作用域(一级缓存Session/二级缓存 Namespaces)进行了新增、修改、删除操作后,该作用域下所有select的缓存数据被清空
- 二级缓存需要缓存的数据必须实现Seaializable接口
- SqlSession会话提交或关闭后,一级缓存的数据才会转移到二级缓存(如下,没有sqlSession1.close(),即使开启二级缓存,这里也会执行两次SQL查询)