mybatis运行原理是什么?
mybatis-plus 实践及架构原理-00000003.PNG
实际上SqlSession的执行过程就是通过Executor、StatementHandler、ParameterHandler、ResultSetHandler这四个对象来完成对数据库的操作和返回结果的。
ResultSet rs =statement.executeQuery(sql);//级别根据这条语句就能判断3大对象
Executor是负责调用语句执行的。

  1. public SqlSessionFactory getSqlSessionFactory() throws IOException{
  2. String resource="mybatis-config.xml";
  3. InputStream inputStream=Resources.getResourceAsStream(resource);
  4. return new SqlSessionFactoryBuilder().build(inputStream);
  5. }
  6. @Test
  7. public void test01() throws IOException{
  8. //1、获取sqlSessionFactory对象
  9. SqlSessionFactory sqlSessionFactory= getSqlSessionFactory();
  10. //2、获取sqlSession对象
  11. SqlSession openSession =sqlSessionFactory.openSession();
  12. try{
  13. //3、获取接口的实现类对象
  14. //会为接口自动的创建一个代理对象(MapperProxy),代理对象去执行增删改查方法
  15. EmployeeMapper mapper=openSession.getMapper(EmployeeMapper.class);
  16. Employee employee=mapper.getEmpById(2);
  17. System.out.println(mapper.getClass());
  18. System.out.println(employee);
  19. }finally {
  20. openSession.close();
  21. }
  22. }

构建SqlSessionFactory

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

  • 解析配置文件,放入Configuration
  • 构造SqlSessionFactory

image.png
image.png
image.png

  • 读取各mapper.xml文件,解析mapper文件。

    MappedStatement

  • 每一条sql语句封装成一个MappedStatement对象。

image.png

  • MappedStatement放入SqlSessionFactory.Configuration对象中,之后会传递到SqlSession对象中。

Configuration中一个map来存放MappedStatement,key是接口的路径(namespace+id)。
image.png

MapperProxyFactory

  • 在Configuration.mapperRegister中还注册了每个接口的MapperProxyFactory

image.png
image.png

构建sqlsession

SqlSession openSession =sqlSessionFactory.openSession();
SqlSession最终交给Executor具体干活。
image.png

创建Executor【拦截器】

创建SqlSession前先创建Executor。
image.png

  • 根据配置创建对应的Executor对象(SimpleExecutor、ReuseExecutor、BatchExecutor、CachingExecutor)
    • 创建Executor时,会应用interceptor

image.png
创建出的Executor最终放入SqlSession中。
SqlSession对象内部有

  • Configuration
  • Executor

image.png

SqlSession直接操作情况(不获取Mapper)

image.png

getMapper

image.png
image.png
EmployeeMapper mapper=openSession.getMapper(EmployeeMapper.class);
返回的Mapper就是一个被MapperProxy包装的动态代理。
image.png

  • 通过Configuration.mapperRegister,其中有knowMappers(Map)根据类名找到对应的的MapperProxyFactory
  • MapperProxyFactory通过动态代理构建Mapper(MapperProxy代理)

image.png

MapperProxy(InvocationHandler)

image.png
代理对象Mapper:
image.png

调用Mapper方法

image.png
mybatis运行原理是什么?

1.MapperProxy动态代理方法调用,交给sqlSession

Employee employee=mapper.getEmpById(2);
实际是调用动态代理MapperProxy的invoke()方法。
调用mapperMethod.execute(sqlSession, args);
image.png
image.png

  • ParamNameResolver处理传入参数:

    • 单个参数直接返回。
    • 多个参数,包装为map返回。

      2.调用SqlSession.selectOne(),交给executor处理

      selectOne()中
  • 从Configuration中获取MappedStatement

  • 调用Executor
  • 调用selectOne()也是调用selectList()

image.png
也可以手动直接调用sqlsession.selectOne(),MapperProxy的目的就是为了调用方便

3.执行Executor

Executor类型

image.png
image.png

Mybatis一、二级缓存

image.png

一级缓存【SESSION和STATEMENT】

什么时候命中一级缓存:

  • 同一个SqlSession
  • 相同的StatementID
  • 参数相同

一级缓存:

通过整合Spring后我们发现,我们的SqlSession对象被偷梁换柱了,换成了SqlSessionTemplate类
因为Spring只有在开启了事务之后,在同一个事务里的SqlSession会被缓存起来,同一个事务中,多次查询是可以命中缓存的
image.png

二级缓存【namespace】

开启二 级缓存

image.png

  • 默认cacheEnabled=true
  • sqlSession.commit() 才放入缓存。
  • image.png

image.png
image.png
二级缓存:

  • SqlSession之间缓存数据
  • 缓存是以namespace为单位的,不同namespace下的操作互不影响。
    • 例如在UserMapper.xml中有大多数针对user表的操作。但是在另一个XXXMapper.xml中,还有针对user单表的操作。这会导致user在两个命名空间下的数据不一致
  • insert,update,delete操作会清空所在namespace下的全部缓存。
  • 同一个Mapper中的MappedStatement中的cache属性引用同一个对象。
  • 不推荐使用mybatis二级缓存


二级缓存种类

BlockingCache
image.png
FifoCache
一个队列用来记录cache的顺序。
image.png
LruCache
LruCache使用LinkedHashMap来维护Lru
image.png
image.png
SoftCache
使用软引用

Executor查询流程

  • 先调用CachingExecutor,
    • 获取BoundSql
    • 处理二级缓存

image.png

  • 再调用SimpleExecutor、ReuseExecutor、BatchExecutor中的一种的doQuery()

    StatementHandler:创建出Statement对象

    image.png
    三种StatementHandler:
    一般都用PreparedStatementHandler
    image.png

    StatementHandler执行流程

    image.png

    1. 创建StatementHandler【拦截器】

  • 根据Configuration,创建statementHandler(PreparedStatementHandler)

image.png
创建statementHandler过程中会创建ParameterHandler和ResultSetHandler。
Mybatis插件就是通过拦截器,返回动态代理

2. 创建ParameterHandler和ResultSetHandler【拦截器】

创建过程会被拦截器拦截
image.png

3. 创建Statement,包括使用ParameterHandler设置参数

  • 其中包括使用ParameterHandler设置参数
    • 设置参数时会用到TypeHandler

image.png
image.png

4. 执行StatementHandler.query(),PreparedStatement查询,ResultSetHandler处理结果

  • 就是PreparedStatement#execute
  • 然后ResultSetHandler处理结果

PreparedStatementHandler#query
image.png
image.png
image.png

Configuration

image.png
image.png

延迟加载

局部延迟加载:
image.png
全局延迟加载:
image.png
原理:通过动态代理,拦截方法,加载数据。

Mybatis和Spring整合

SqlSessionFactoryBean构造Configuration,DefaultSqlSessionFactory

SqlSessionFactoryBean#afterPropertiesSet

  • this.sqlSessionFactory = buildSqlSessionFactory();
    • 先构建Configuration,将Configuration传入DefaultSqlSessionFactory

MapperFactoryBean:配置mapper

spring中需要配置
image.png

  1. public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T>

image.png
spring帮我们调用了sqlSession.getMapper()操作。
每一个mapper单独配置太麻烦了,所以要引入MapperScannerConfigurer,自动扫描mapper

MapperScannerConfigurer(BeanDefinitionRegistryPostProcessor):自动扫描mapper

image.png
MapperScannerConfigurer是一个BeanDefinitionRegistryPostProcessor。
image.png
MapperScannerConfigurer(BeanDefinitionRegistryPostProcessor)会再spring启动时用来注册BeanDefinition。
这里扫描mapper包
image.png
ClassPathMapperScanner#processBeanDefinitions
image.png
最终注册的是MapperFactoryBean的BeanDefinition。【为什么是FactoryBean,因为sqlSession这时候还没有】
通过RuntimeBeanReference来引用SqlSessionFactory。
SqlSessionFactory在AutoConfiguration中已经注册了。

@MapperScan:加载MapperScannerConfigurer BeanDefinition

之前为手动加载mybatis-config.xml。spring需要自动将Mapper纳入到容器中。
image.png

  1. @MapperScan引入MapperScannerRegistrar.class
  2. MapperScannerRegistrar中创建MapperScannerConfigurer

image.png
MapperScannerConfigurer看上面。

Mybatis和Springboot整合总结

总结:SqlSessionFactory中解析xml,@MapperScan负责包装MapperProxyFactory到Spring容器。
MapperProxyFactory中关联SqlSessionFactory。
注册到Spring这样省去了EmployeeMapper mapper=openSession.getMapper(EmployeeMapper.class);这一步。Mapper从容器中获取。

Spring通过SqlSessionTemplate来保证SqlSession线程安全

如何保证SqlSession的线程安全? - SegmentFault 思否
SqlSessionTemplate持有SqlSession动态代理对象。

一对多分页查询总数不对问题

mybatis-一对多分页查询_zjun1001的博客-CSDN博客_mybatis 一对多分页