mybatis源码学习

一、整体架构

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
SqlSession是接口,里面各种增删改查接口,Executor里面是具体的实现

SimpleExecutor
 @Test
    public void test1() throws SQLException {
        SimpleExecutor executor = new SimpleExecutor(configuration, jdbcTransaction);
        //mapper中对应的方法
        MappedStatement ms = configuration.getMappedStatement("com.alipay.mybatis.persion.mapper.PersonMapper.findALl");
        List<Person> es = executor.doQuery(ms, 2, RowBounds.DEFAULT,SimpleExecutor.NO_RESULT_HANDLER, ms.getBoundSql(2));
        executor.doQuery(ms, 2, RowBounds.DEFAULT,SimpleExecutor.NO_RESULT_HANDLER, ms.getBoundSql(2));
        System.out.println(es.get(1));
    }

在这里插入图片描述
可见进行了两次预处理

ReuseExecutor
@Test
    public void test2() throws SQLException {
        ReuseExecutor executor = new ReuseExecutor(configuration, jdbcTransaction);
        //mapper中对应的方法
        MappedStatement ms = configuration.getMappedStatement("com.alipay.mybatis.persion.mapper.PersonMapper.findALl");
        List<Person> es = executor.doQuery(ms, 2, RowBounds.DEFAULT,SimpleExecutor.NO_RESULT_HANDLER, ms.getBoundSql(2));
        executor.doQuery(ms, 2, RowBounds.DEFAULT,SimpleExecutor.NO_RESULT_HANDLER, ms.getBoundSql(2));
        System.out.println(es.get(1));
    }

在这里插入图片描述
只进行了一次预处理

BatchExexutor

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
对于修改操作进行批处理,只编译一次
在这里插入图片描述
BaseExecutor中定义了下面三个执行器中的一些公共方法,如获取连接,缓存
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

 @Test
    public void test3() throws SQLException {
        Executor executor = new SimpleExecutor(configuration, jdbcTransaction);
        //mapper中对应的方法
        MappedStatement ms = configuration.getMappedStatement("com.alipay.mybatis.persion.mapper.PersonMapper.findALl");
        executor.query(ms, 2, RowBounds.DEFAULT,Executor.NO_RESULT_HANDLER);
        executor.query(ms, 2, RowBounds.DEFAULT,SimpleExecutor.NO_RESULT_HANDLER);

    }

在这里插入图片描述
可见只进行了一次编译,是因为query中有缓存的操作

BaseExecutor的query方法
@Override
  public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    BoundSql boundSql = ms.getBoundSql(parameter);//获取动态sql
    CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);//获取缓存的key
    return query(ms, parameter, rowBounds, resultHandler, key, boundSql);//调用重载
  }

//重载的query
@Override
  public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
    if (closed) {
      throw new ExecutorException("Executor was closed.");
    }
    if (queryStack == 0 && ms.isFlushCacheRequired()) {
      clearLocalCache();
    }
    List<E> list;
    try {
      queryStack++;
      list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;//获取本地一级缓存
      if (list != null) {
      //如果有缓存
        handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
      } else {
      //如果没有缓存
        list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
      }
    } finally {
      queryStack--;
    }
    if (queryStack == 0) {
      for (DeferredLoad deferredLoad : deferredLoads) {
        deferredLoad.load();
      }
      // issue #601
      deferredLoads.clear();
      if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
        // issue #482
        clearLocalCache();
      }
    }
    return list;
  }

//BaseExecutor

private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    List<E> list;
    localCache.putObject(key, EXECUTION_PLACEHOLDER);
    try {
    //走到了doQuery方法
      list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
    } finally {
      localCache.removeObject(key);
    }
    localCache.putObject(key, list);
    if (ms.getStatementType() == StatementType.CALLABLE) {
      localOutputParameterCache.putObject(key, parameter);
    }
    return list;
  }


//SimpleExecutor
@Override
  public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    Statement stmt = null;
    try {
      Configuration configuration = ms.getConfiguration();
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }

二级缓存

在这里插入图片描述
二级缓存的实现在CachingExecutor里面实现,采用装饰着模式

二级缓存需要自己来配,属于外部缓存

 @Test
    public void test4() throws SQLException {
        Executor executor = new SimpleExecutor(configuration, jdbcTransaction);
        //走二级缓存
        CachingExecutor cachingExecutor = new CachingExecutor(executor);
        //mapper中对应的方法

        cachingExecutor.query(ms, 2, RowBounds.DEFAULT,Executor.NO_RESULT_HANDLER);
        cachingExecutor.commit(true);//先走二级缓存再走一级缓存,由于我没有配二级缓存所以不会生效
        cachingExecutor.query(ms, 2, RowBounds.DEFAULT,Executor.NO_RESULT_HANDLER);
    }

@Override
  public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    BoundSql boundSql = ms.getBoundSql(parameterObject);
    CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
    return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

  @Override
  public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
      throws SQLException {
    Cache cache = ms.getCache();
    if (cache != null) {//判断你有没有配二级缓存,有就走下面逻辑
    //清空二级缓存的操作
      flushCacheIfRequired(ms);
      //判断你的缓存是否是打开的
      if (ms.isUseCache() && resultHandler == null) {
        ensureNoOutParams(ms, boundSql);
        @SuppressWarnings("unchecked")
        //获取缓存的内容
        List<E> list = (List<E>) tcm.getObject(cache, key);
        //如果缓存的内容为空
        if (list == null) {
        //交给下一个执行器,就是BaseExecutor
          list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
          tcm.putObject(cache, key, list); // issue #578 and #116
        }
        return list;
      }
    }
    //没有就走一级缓存,一级缓存定义在BaseExecutor   就是BaseExecutor
    return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

在这里插入图片描述
在这里插入图片描述

小总结

SqlSession中的方法会间接调用executor的query方法,在CachingExecutor中的query实现了该方法,里面有二级缓存的逻辑,然后里面的delegate指向下一个执行器BaseExecutor,里面有一级缓存和获取连接等操作,调用query方法,query方法里面又有doQuery方法,这个doQuery方法由下面三个类中的一个来实现

通过sqlsession来调用

在这里插入图片描述

在这里插入图片描述

清空缓存的操作

**加粗样式
**
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
一级缓存失效的情况,是你用spring没有用到事务,只要把查询都写到一个事务里面,缓存就会生效,一个事务对应一个连接,一个连接就对应一次会话
在这里插入图片描述

spring是如何调用mybatis的工厂的

在这里插入图片描述

mybatis缓存体系

在这里插入图片描述
在这里插入图片描述
会话不是线程安全的,所以一级缓存也不是线程安全的,所以无法跨线程使用
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
commit应该加在后面
在这里插入图片描述

StatementHandler

在这里插入图片描述
一个SqlSession对应一个Executor对应多个个StatementHandler

StatementHandler的定义

在这里插入图片描述
在这里插入图片描述

结果集映射在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

ResultSetHandler->DefaultResultSetHandler

Mybatis映射体系

结果集和Java对象的一个互相的映射

MeataObject结果集映射工具类

在这里插入图片描述
我们可以采用工具类就可以直接把object转化为Blog类
在这里插入图片描述
在这里插入图片描述
Author是一个类,可以给里面的属性name赋值
在这里插入图片描述
在这里插入图片描述

MetaObject源码解析

结果集映射ResultMap

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

动态sql

在这里插入图片描述
在这里插入图片描述

SqlSource解析流程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

SqlNode语法树结构

在这里插入图片描述

Configuration配置体系

在这里插入图片描述

Configuration核心功能

在这里插入图片描述
在这里插入图片描述

Configuration组件的构建过程

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

MappedStatement的解析

它是解析sql的所以比较核心
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

插件的四大组件

在这里插入图片描述
在这里插入图片描述

分页插件编码

在这里插入图片描述
在这里插入图片描述
就是在预处理的时候对它进行一个拦截
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

### 回答1: MyBatis 是一个开源的持久层框架,可以方便地将 SQL 语句和 Java 对象进行映射。如果您想要学习 MyBatis 源码,可以按照以下步骤进行: 1. 了解 MyBatis 的架构和设计原理。可以阅读官方文档和相关书籍,例如《MyBatis 技术内幕》。 2. 下载 MyBatis 的源代码,并导入到 IDE 中。MyBatis 使用 Maven 进行构建,您可以使用 IDE 的 Maven 插件来下载依赖项。 3. 查看 MyBatis 的源代码结构。MyBatis 的主要代码在 `mybatis-3` 模块中,包括 `src/main/java` 和 `src/main/resources` 目录。其中,`src/main/java` 目录包含了 MyBatis 的核心代码,例如 `org.apache.ibatis.session.SqlSession` 类;`src/main/resources` 目录包含了 MyBatis 的配置文件和映射文件。 4. 阅读 MyBatis 的源代码。可以从 MyBatis 的入口处 `org.apache.ibatis.session.SqlSessionFactoryBuilder` 开始,深入了解 MyBatis 的初始化流程、SQL 语句的执行流程、映射文件的解析和缓存等。 5. 调试 MyBatis 的源代码。可以使用 IDE 的调试功能,对 MyBatis 进行单步调试,观察代码的执行流程,加深对 MyBatis 的理解。 6. 学习 MyBatis 的单元测试。MyBatis 的单元测试位于 `src/test/java` 目录中,可以通过单元测试来了解 MyBatis 的各个功能点的使用方法和测试用例。 7. 参与 MyBatis 的开发。如果您对 MyBatis 源码有深入的了解,并希望为 MyBatis 做出贡献,可以参与 MyBatis 的开发,贡献代码和文档,提交 issue 和 PR。MyBatis 的开发社区非常活跃,可以在官方网站和 GitHub 上找到相关信息。 希望这些步骤对您学习 MyBatis 源码有所帮助。 ### 回答2: MyBatis是一个开源的Java持久层框架,通过操作对象与数据库关系映射来提供数据持久化的功能。了解MyBatis源码学习和使用该框架的重要一步。 首先,MyBatis源码结构比较清晰,主要分为核心模块和附属模块。核心模块包括XML配置解析、SQL语句解析、参数处理、数据库连接管理等功能的实现,是实现MyBatis基本功能的核心部分。附属模块包括缓存、事务、插件等额外功能的实现,可以根据需要进行扩展和配置。 学习MyBatis源码可以从以下几个方面入手: 1. 配置文件解析:MyBatis通过XML配置文件来进行相关的配置,了解配置文件的解析过程可以帮助理解MyBatis的初始化过程和各项配置的作用。 2. SQL语句解析与执行:MyBatis将SQL语句封装成MappedStatement对象进行管理,了解MappedStatement的生成过程,以及SQL语句的解析、参数处理和执行过程,可以深入了解MyBatis的SQL执行原理。 3. 会话管理和事务处理:MyBatis采用SqlSessionFactory和SqlSession来管理数据库连接和事务,在MyBatis源码中可以学习到如何管理数据库连接池、事务的提交和回滚等核心功能的实现。 4. 缓存机制:MyBatis提供了一级缓存和二级缓存的功能,了解缓存的生成和更新过程,以及缓存的命中和失效原理,可以提高数据库查询性能。 总之,通过学习MyBatis源码,可以加深对该框架的理解,掌握其内部实现原理,有助于在使用时更加灵活和高效地进行开发。同时,也为以后解决一些特殊问题提供了更多的思路和方法。 ### 回答3: MyBatis是一个优秀的持久层框架,学习源码有助于理解其底层原理和设计思想。 首先,可以从MyBatis的入口开始学习,即SqlSessionFactoryBuilder类。该类负责解析配置文件、创建Configuration对象,并通过Configuration对象创建SqlSessionFactory实例。 接下来,可以学习Configuration类,该类负责管理整个MyBatis的配置信息。其中包括了数据库连接信息、映射文件信息、缓存信息等。在该类内部,会调用XMLMapperBuilder类解析映射文件,在解析映射文件过程中,会创建MappedStatement对象,该对象表示一条SQL语句的映射信息。 学习MappedStatement对象可以了解MyBatis的SQL语句解析过程。该对象包含了SQL语句的相关信息,包括参数映射关系、返回结果映射关系等。在执行SQL语句时,会使用ParameterHandler类处理参数,通过ResultSetHandler类处理查询结果。 同时,学习到Executor接口及其实现类,可以了解MyBatis的执行过程。Executor负责执行SQL语句,其中包括了写操作的update方法和读操作的query方法。在执行过程中,会通过StatementHandler类创建PreparedStatement对象,并通过ResultSetHandler类处理执行结果。 最后,还可以学习MyBatis的事务处理和缓存机制。Transaction接口及其实现类负责事务管理,通过JDBC的事务机制实现了事务的提交和回滚。而Cache接口及其实现类负责缓存查询结果,在查询时会先从缓存中查找结果。 总结来说,通过学习MyBatis源码可以深入理解其底层原理和设计思想。从SqlSessionFactory的创建开始,到Configuration的配置解析、MappedStatement的创建,再到Executor的执行过程和Transaction的事务管理,以及Cache的缓存机制,逐步掌握MyBatis的各个组件和它们之间的交互关系。这对于我们使用MyBatis开发项目,解决问题和优化性能都具有积极的意义。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值