能说说MyBatis的工作原理吗?

我们已经大概知道了MyBatis的工作流程,按工作原理,可以分为两大步:生成会话工厂会话运行

MyBatis是一个成熟的框架,篇幅限制,这里抓大放小,来看看它的主要工作流程。

构建会话工厂

  • 获取配置

获取配置这一步经过了几步转化,最终由生成了一个配置类Configuration实例,这个配置类实例非常重要,主要作用包括:

  • 读取配置文件,包括基础配置文件和映射文件
  • 初始化基础配置,比如MyBatis的别名,还有其它的一些重要的类对象,像插件、映射器、ObjectFactory等等
  • 提供一个单例,作为会话工厂构建的重要参数
  • 它的构建过程也会初始化一些环境变量,比如数据源
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
      SqlSessionFactory var5;
      //省略异常处理
          //xml配置构建器
          XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
          //通过转化的Configuration构建SqlSessionFactory
          var5 = this.build(parser.parse());
}
  • 构建SqlSessionFactory

SqlSessionFactory只是一个接口,构建出来的实际上是它的实现类的实例,一般我们用的都是它的实现类DefaultSqlSessionFactory,

public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
}

会话运行

会话运行是MyBatis最复杂的部分,它的运行离不开四大组件的

  • Executor(执行器)

Executor起到了至关重要的作用,SqlSession只是一个门面,相当于客服,真正干活的是是Executor,就像是默默无闻的工程师。它提供了相应的查询和更新方法,以及事务方法。

Environment environment = this.configuration.getEnvironment();
TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//通过Configuration创建executor
Executor executor = this.configuration.newExecutor(tx, execType);
var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
  • StatementHandler(数据库会话器)

StatementHandler,顾名思义,处理数据库会话的。我们以SimpleExecutor为例,看一下它的查询方法,先生成了一个StatementHandler实例,再拿这个handler去执行query。

 public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    Statement stmt = null;

    List var9;
    try {
        Configuration configuration = ms.getConfiguration();
        StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
        stmt = this.prepareStatement(handler, ms.getStatementLog());
        var9 = handler.query(stmt, resultHandler);
    } finally {
        this.closeStatement(stmt);
    }

    return var9;
}

再以最常用的PreparedStatementHandler看一下它的query方法,其实在上面的prepareStatement已经对参数进行了预编译处理,到了这里,就直接执行sql,使用ResultHandler处理返回结果。

public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    PreparedStatement ps = (PreparedStatement)statement;
    ps.execute();
    return this.resultSetHandler.handleResultSets(ps);
}
  • ParameterHandler (参数处理器)

PreparedStatementHandler里对sql进行了预编译处理

public void parameterize(Statement statement) throws SQLException {
    this.parameterHandler.setParameters((PreparedStatement)statement);
}

这里用的就是ParameterHandler,setParameters的作用就是设置预编译SQL语句的参数。

里面还会用到typeHandler类型处理器,对类型进行处理。

public interface ParameterHandler {
    Object getParameterObject();

    void setParameters(PreparedStatement var1) throws SQLException;
}
  • ResultSetHandler(结果处理器)

我们前面也看到了,最后的结果要通过ResultSetHandler来进行处理,handleResultSets这个方法就是用来包装结果集的。Mybatis为我们提供了一个DefaultResultSetHandler,通常都是用这个实现类去进行结果的处理的。

public interface ResultSetHandler {
  <E> List<E> handleResultSets(Statement var1) throws SQLException;

  <E> Cursor<E> handleCursorResultSets(Statement var1) throws SQLException;

  void handleOutputParameters(CallableStatement var1) throws SQLException;
}

整体工作流程如下:

  1. 读取MyBatis的配置文件(mybatis-config.xml)和映射文件(SQL映射文件),生成配置对象。
  2. 构建会话工厂(SqlSessionFactory):使用配置对象,创建会话工厂,会话工厂是生成会话(SqlSession)的工厂类。
  3. 创建会话(SqlSession):通过会话工厂创建会话对象,会话对象包含执行SQL语句的方法。
  4. 执行器(Executor):会话对象使用执行器来操作数据库。执行器根据传递的参数动态生成需要执行的SQL语句,并负责查询缓存的管理。
  5. 语句处理器(StatementHandler):负责处理SQL语句的参数映射和结果映射,将参数传递给数据库并执行SQL语句。
  6. 参数处理:处理输入参数的类型,并进行预编译。
  7. 结果处理:根据对象映射规则,将数据库返回的结果映射为相应的对象。

标签: java, Java面试题, mybatis, Java问题合集, Java编程, Java问题精选, Java常见问题, MyBatis面试题