Mybatis核心类讲解

Mybatis核心类讲解

在这里插入图片描述

SqlSessionFactoryBuilder

每一个MyBatis的应用程序的入口是SqlSessionFactoryBuilder。它的作用是通过XML配置文件创建Configuration对象,然后通过build方法创建SqlSessionFactory对象。可以做到全局只有一个就行。不需要每次都创建。

SqlSessionFactory

SqlSessionFactory的主要功能是创建SqlSession对象,和SqlSessionFactoryBuilder对象一样,没有必要每次访问Mybatis就创建一次SqlSessionFactory,通常的做法是创建一个全局的对象就可以了。

SqlSession

SqlSession类的主要功能是完成一次数据库的访问和结果的映射,它类似于一次会话概念,顾命名为:SqlSession。

SqlSession类似于JDBC里面的Connection,Connection不是线程安全的,SqlSession也不是线程安全的。由于不是线程安全的,所以SqlSession对象的作用域需限制方法内。

SqlSession的默认实现类是DefaultSqlSession,它有两个必须配置的属性:Configuration和Executor。mybatis-config.xml中的配置,最后会解析xml成Configuration这个类。SqlSession对数据库的操作都是通过Executor来完成的。

SqlSession有一个重要的方法getMapper,顾名思义,这个方式是用来获取Mapper映射器的。

SqlSession有很多增删改查的方法。

Executor

在这里插入图片描述

BaseExecutor: BaseExecutor是一个抽象类,采用模板方法的设计模式。它实现了Executor接口,实现了执行器的基本功能。具体使用哪一个Executor则是可以在 mybatis 的 config.xml 中进行配置的。默认为SimpleExecutor;

**SimpleExecutor:**最简单的执行器,根据对应的sql直接执行即可,不会做一些额外的操作;

BatchExecutor: 通过批量操作来优化性能。通常需要注意的是批量更新操作,由于内部有缓存的实现,使用完成后记得调用flushStatements来清除缓存。

**ReuseExecutor :**重用的执行器,重用的对象是Statement,也就是说该执行器会缓存同一个sql的Statement,省去Statement的重新创建,优化性能。内部的实现是通过一个HashMap来维护Statement对象的。由于当前Map只在该session中有效,所以使用完成后记得调用flushStatements来清除Map。调用实现的四个抽象方法时会调用 prepareStatement() ;

**CachingExecutor:**启用于二级缓存时的执行器;采用静态代理;代理一个 Executor 对象。执行 update 方法前判断是否清空二级缓存;执行 query 方法前先在二级缓存中查询,命中失败再通过被代理类查询。

**ClosedExecutor:**也继承了BaseExecutor抽象类,且是ResultLoaderMap类中的一个内部类,用于实现懒加载相关逻辑

/**
 * 执行器
 * @author Clinton Begin
 */
public interface Executor {

  ResultHandler NO_RESULT_HANDLER = null;

  // insert | update | delete 语句执行
  int update(MappedStatement ms, Object parameter) throws SQLException;

  // select
  <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;

  // select
  <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;

  // select 返回游标
  <E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException;

  // 批量
  List<BatchResult> flushStatements() throws SQLException;

  // 提交事务
  void commit(boolean required) throws SQLException;

  // 回滚
  void rollback(boolean required) throws SQLException;

  // 创建缓存中使用的 CacheKey
  CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);

  // 根据 CacheKey 查找缓存
  boolean isCached(MappedStatement ms, CacheKey key);

  // 清空一级缓存
  void clearLocalCache();

  // 延迟加载一级缓存中的数据
  void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType);

  // 获取事务
  Transaction getTransaction();

  // 关闭 Executor 对象
  void close(boolean forceRollback);

  // 是否已经关闭
  boolean isClosed();

  void setExecutorWrapper(Executor executor);
}

Executor对象在创建Configuration对象的时候创建,并且缓存在Configuration对象里。

Executor对象的主要功能是调用StatementHandler访问数据库。

StatementHandler

在这里插入图片描述

BaseStatementHandler:是 StatementHandler 接口的另一个实现类.本身是一个抽象类.用于简化StatementHandler 接口实现的难度,属于适配器设计模式体现,它主要有三个实现类

SimpleStatementHandler: 管理 Statement 对象并向数据库中推送不需要预编译的SQL语句

PreparedStatementHandler: 管理 Statement 对象并向数据中推送需要预编译的SQL语句,

CallableStatementHandler:管理 Statement 对象并调用数据库中的存储过程

**RoutingStatementHandler:**RoutingStatementHandler 并没有对 Statement 对象进行使用,只是根据StatementType 来创建一个代理,代理的就是上述的三种实现类。

/**
 * 使用了策略模式的一个 StatementHandler 实现, 其最终调用的是实际 StatementHandler 的方法
 */
public class RoutingStatementHandler implements StatementHandler {
  // 真正的 Statement 对象
  private final StatementHandler delegate;
  /**
   * 根据指定的类型,创建对应的接口实现
   */
  public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    switch (ms.getStatementType()) {
      case STATEMENT:
        delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case PREPARED:
        delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case CALLABLE:
        delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      default:
        throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
    }
  }
/**
 * 核心类, 与执行相关
 */
public interface StatementHandler {
  // 从连接中获取一个 statement
  Statement prepare(Connection connection, Integer transactionTimeout)
      throws SQLException;

  // 绑定 statement 执行时所需要的参数
  void parameterize(Statement statement)
      throws SQLException;

  // 批量
  void batch(Statement statement)
      throws SQLException;

  // update|delete|insert
  int update(Statement statement)
      throws SQLException;

  // 查询 select
  <E> List<E> query(Statement statement, ResultHandler resultHandler)
      throws SQLException;

  // 游标查询
  <E> Cursor<E> queryCursor(Statement statement)
      throws SQLException;

   // 获取绑定的 sql
  BoundSql getBoundSql();

  // 获取封装的 PrameterHandler
  ParameterHandler getParameterHandler();
}

StatementHandler对象的创建

StatementHandler 对象是在 SqlSession 对象接收到命令操作时,由 Configuration 对象中的newStatementHandler 负责调用的,也就是说 Configuration 中的 newStatementHandler 是由执行器中的查询、更新(插入、更新、删除)方法来提供的,StatementHandler 其实就是由 Executor 负责管理和创建的。

/**
 * 简单Executor实现类
 */
public class SimpleExecutor extends BaseExecutor {

  public SimpleExecutor(Configuration configuration, Transaction transaction) {
    super(configuration, transaction);
  }
  /**
   * 更新(insert | udpdate | delete)实现
   * @param ms
   * @param parameter
   * @return
   * @throws SQLException
   */
  @Override
  public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
    Statement stmt = null;
    try {
      // 获取配置
      Configuration configuration = ms.getConfiguration();
      // 获取 StatementHandler
      StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
      // 准备 Statement
      stmt = prepareStatement(handler, ms.getStatementLog());
      // 执行
      return handler.update(stmt);
    } finally {
      // 关闭
      closeStatement(stmt);
    }
  }
  /**
   * 查询
   */
  @Override
  public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    // 使用 Statement
    Statement stmt = null;
    try {
      // 获取配置对象
      Configuration configuration = ms.getConfiguration();
      // 获取对应的 StatementHandler
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      // Statement 初始化
      stmt = prepareStatement(handler, ms.getStatementLog());
      // 查询并完成结果映射
      return handler.<E>query(stmt, resultHandler);
    } finally {
      // 关闭
      closeStatement(stmt);
    }
  }
  /**
   * 查询, 游标
   */
  @Override
  protected <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql) throws SQLException {
    Configuration configuration = ms.getConfiguration();
    StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, null, boundSql);
    Statement stmt = prepareStatement(handler, ms.getStatementLog());
    return handler.<E>queryCursor(stmt);
  }
  /**
   * 返回空集合, 即不处理批处理
   */
  @Override
  public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
    return Collections.emptyList();
  }
    
  //2、prepareStatement()
  /**
   * 准备 Statement
   * @param handler
   * @param statementLog
   * @return
   * @throws SQLException
   */
  private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    // 获取连接
    Connection connection = getConnection(statementLog);
    // 调用 handler.prepare() 创建 Statement 对象
    stmt = handler.prepare(connection, transaction.getTimeout());
    // 处理占位符
    handler.parameterize(stmt);
    return stmt;
  }
}

//1、configuration.newStatementHandler()
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
    return statementHandler;
}
  1. 源代码可以看出StatementHandler 默认创建一个 RoutingStatementHandler ,这也就是 StatementHandler 的默认实现,由 RoutingStatementHandler 负责根据 StatementType 创建对应的StatementHandler 来处理调用。而且也会走拦截器调用链。
  2. 通过prepareStatement()方法,先是获取到数据库连接,然后通过调用链可以看到会去调用 instantiateStatement() 方法,instantiateStatement 方法位于 StatementHandler 中,是一个抽象方法由子类去实现,实际执行的是三种 StatementHandler 中的一种,我们还以 SimpleStatementHandler 为例
  /**
   * 初始化 Statement 对象, 通过 Connection 进行创建
   */
  @Override
  protected Statement instantiateStatement(Connection connection) throws SQLException {
    if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
      return connection.createStatement();
    } else {
      return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    }
  }

经过一系列的调用会把statement 对象返回到 SimpleExecutor 简单执行器中,为 parametersize 方法所用。

但是这个时候看到SimpleStatementHandler里面的parameterize 是一个空实现。原因是因为:SimpleStatementHandler 只负责处理简单SQL,能够直接查询得到结果的SQL,例如:select a from bSimpleStatementHandler不涉及参数赋值的问题,所以这个时候应该看**PreparedStatementHandler**

  1. 通过*org.apache.ibatis.scripting.defaults.DefaultParameterHandler#setParameters* 绑定具体的参数
  2. 执行查询或者更新语句。根据不同的执行器对象使用不同的statement执行sql语句。
org.apache.ibatis.executor.statement.SimpleStatementHandler#query
  /**
   * 查询
   */
  @Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    // 获取 SQL 语句
    String sql = boundSql.getSql();
    // 执行 SQL 语句
    statement.execute(sql);
    // 处理结果集
    return resultSetHandler.<E>handleResultSets(statement);
  }
  org.apache.ibatis.executor.statement.PreparedStatementHandler#query
    /**
   * 查询
   */
  @Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();
    return resultSetHandler.<E> handleResultSets(ps);
  }
  org.apache.ibatis.executor.statement.CallableStatementHandler#query
    /**
   * 查询
   */
  @Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    CallableStatement cs = (CallableStatement) statement;
    cs.execute();
    List<E> resultList = resultSetHandler.<E>handleResultSets(cs);
    resultSetHandler.handleOutputParameters(cs);
    return resultList;
  }

ResultSetHandler

/**  
 * 结果集处理      只有一个实现类 org.apache.ibatis.executor.resultset.DefaultResultSetHandler
 */
public interface ResultSetHandler {
  // 处理生成的结果集
  <E> List<E> handleResultSets(Statement stmt) throws SQLException;
  // 梳理结果集, 返回相应的游标对象
  <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;
  // 处理存储过程的输出函数
  void handleOutputParameters(CallableStatement cs) throws SQLException;
}

这个类也是比较复杂的一个,除了正常的对象属性映射,还需要处理一对一,一对多的。

在这里插入图片描述

TypeHandler

负责Java数据类型和JDBC数据类型之间的映射和转换。Mybatis内置了很多类型处理器(TypeHandlerRegistry )自己也可以自定类型处理器。

SqlSource

负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回。

BoundSql

表示动态生成的SQL语句以及相应的参数信息

Configuration

MyBatis所有的配置信息都维持在Configuration对象之中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值