美文网首页
Mybatis核心对象和执行流程

Mybatis核心对象和执行流程

作者: Johnny_ | 来源:发表于2019-02-17 10:11 被阅读0次

Mybatis重要对象

SqlSessionFactory

SqlSessionFactory是mybatis的核心对象,是一个数据库连接的抽象,通过他可以执行一次又一次的数据库操作。SqlSessionFactoryBuilder是专门用于构造SqlSessionFactory的工厂,其通过build函数的重载,支持以不同的方式创建SqlSessionFactory:

image

其中的InputStream是字节流,Reader是字符流,也可以通过自己定义一个Configuration定义数据库连接的相关信息完成SqlSessionFactory的构造。environment用于指定加载哪种环境的配置:

<environments default="development">
  <environment id="development">
    <transactionManager type="JDBC">
        ...
    <dataSource type="POOLED">
        ...
  </environment>
  <environment id="production">
    <transactionManager type="MANAGED">
        ...
    <dataSource type="JNDI">
        ...
  </environment>
</environments>

SqlSessionFactory的运行周期应该和应用的运行周期一致,同时,没有必要多次创建SqlSessionFactory,实现时可以使用单例。Mybatis提供了一个默认的实现DefaultSqlSessionFactory

在SqlSessionFactory中,通过openSession的重载,提供了创建不同Session的接口:


image

在mybatis-spring包中,将SqlSessionFactory的构造封装到SqlSessionFactoryBean中,默认就被设置成了单例。

image

SqlSession

SqlSessionFactory的产品,当我们在进行一次数据库操作时,都会构造一个Session,把断点定位到DefaultSqlSessionFactory的openSessionFromDataSource方法可以跟踪每一次的数据库操作。SqlSession是非线程安全的,不能被共享。所以,SqlSession的实例不能是静态的,也不能共享到容器中,甚至是类的实例变量也不行。创建SqlSession的过程如下:

  private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      final Environment environment = configuration.getEnvironment();
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      final Executor executor = configuration.newExecutor(tx, execType);
      return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
      closeTransaction(tx); // may have fetched a connection so lets call close()
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

  1. 从配置中获取环境参数
  2. 从环境获取事务
  3. 从环境中获取数据源
  4. 通过配置构造执行器Executor
  5. 构造DefaultSqlSession

其中的执行器Executor是最终操作数据库的对象,SqlSession算是把一次数据操作当做一次回话后对外的封装。有三种类型的Executor:

  public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    Executor executor;
    if (ExecutorType.BATCH == executorType) {
      executor = new BatchExecutor(this, transaction);
    } else if (ExecutorType.REUSE == executorType) {
      executor = new ReuseExecutor(this, transaction);
    } else {
      executor = new SimpleExecutor(this, transaction);
    }
    if (cacheEnabled) {
      executor = new CachingExecutor(executor);
    }
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
  }

BatchExecutor专门用于执行批量的sql操作,ReuseExecutor会复用statement执行sql操作,而SimpleExecutor就是直接执行sql操作,默认是SIMPLE。最终返回的Executor是一个CachingExecutor,默认情况下Mybatis就开启了执行器缓存,CachingExecutor在查询数据库前先查找缓存,若没找到的话调用传入的Executor对象从数据库查询,并将查询结果存入缓存中。

MappedStatement

MappedStatement是mapper文件中一条操作语句的封装,比如<select/insert/delete>,在XMLMapperBuilder的parsePendingStatements中,通过MapperBuilderAssistant进行构造。

SqlSource

public interface SqlSource {

  BoundSql getBoundSql(Object parameterObject);

}

只有一个方法,就是通过用户传递的参数解析出sql,他有四个实现:


image

其中DynamicSqlSource负责动态sql的解析,RawSqlSource负责静态sql的解析,而它们两者都依赖StaticSqlSource来完成功能,ProviderSqlSource允许用户定制sql的解析。这里静态sql指的是仅包含 '#{}'的sql,而动态sql包含动态标签(if,foreach等),SqlSource最终会被MppedStatement消费。

StatementHandler

直接和数据库交互的接口,它利用了ParameterHandler和ResultSetHandler解析sql参数并组装最后的结果,Executor也就是依赖了这个接口完成数据库操作。

public interface StatementHandler {

  Statement prepare(Connection connection, Integer transactionTimeout)
      throws SQLException;

  void parameterize(Statement statement)
      throws SQLException;

  void batch(Statement statement)
      throws SQLException;

  int update(Statement statement)
      throws SQLException;

  <E> List<E> query(Statement statement, ResultHandler resultHandler)
      throws SQLException;

  <E> Cursor<E> queryCursor(Statement statement)
      throws SQLException;

  BoundSql getBoundSql();

  ParameterHandler getParameterHandler();

}

其中的prepare用于预编译sql,parameterize则利用了ParameterHandler进行参数的注入。他有这么几个继承的类:


image
  • RoutingStatementHandler,这是一个封装类,它不提供具体的实现,只是根据Executor的类型,创建不同的类型StatementHandler
  • SimpleStatementHandler,这个类对应于JDBC的Statement对象,用于没有预编译参数的SQL的运行
  • PreparedStatementHandler 这个用于预编译参数SQL的运行
  • CallableStatementHandler 它将实存储过程的调度

BoundSql

存储Mybatis解析MappedStatement后的sql语句以及用于传递的参数,最终会被StatementHandler消费,最终把带占位符的sql和实参合并成最终的sql是在PreparedStatement中。

Mybatis执行流程

从SqlSessionFactoryBean开始,可以抽象成两条线,一条是mapper.xml的解析,一条是数据库语句的执行


image

SqlSession里两条线建立关联的代码:


image

相关文章

网友评论

      本文标题:Mybatis核心对象和执行流程

      本文链接:https://www.haomeiwen.com/subject/hgzweqtx.html