Mybatis源码--StatementHandler源码分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ONROAD0612/article/details/83575584

1 概述

在上一篇文章(Mybatis源码分析--Executor源码分析),我们分析Executor源码的时候就提到了StatementHandler的作用是和数据库对话。当然StatementHandler和数据库对话是依赖于Statement来完成的。在这里随便说一下ParameterHandler和ResultHandler的作用分别是绑定SQL参数和组装最后的结果返回。

2 生成StatementHandler

StatementHandler对象的生成是通过调用Configuration的newStatementHandler函数来完成的。

public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    
	//调用RoutingStatementHandler的构造函数来生成StatementHandler
	StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
    return statementHandler;
  }

从上面的源码我们可想而知,针对StatementHandler对象的生成完全交给了RoutingStatementHandler的构造函数。至于RoutingStatementHandler和StatementHandler的关系,我们下面先来看一看StatementHandler的UML类图。

3 StatementHandler的结构

首先我们直接来看一下StatementHandler的UML类图。

我们再来看一下RoutingStatementHandler的源码。

public class RoutingStatementHandler implements StatementHandler {

  private final StatementHandler delegate;

  public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {

    //通过Statement的类型来构造对应的StatementHandler
    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());
    }

  }

  @Override
  public Statement prepare(Connection connection) throws SQLException {
    return delegate.prepare(connection);
  }

  @Override
  public void parameterize(Statement statement) throws SQLException {
    delegate.parameterize(statement);
  }

  @Override
  public void batch(Statement statement) throws SQLException {
    delegate.batch(statement);
  }

  @Override
  public int update(Statement statement) throws SQLException {
    return delegate.update(statement);
  }

  @Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    return delegate.<E>query(statement, resultHandler);
  }

  @Override
  public BoundSql getBoundSql() {
    return delegate.getBoundSql();
  }

  @Override
  public ParameterHandler getParameterHandler() {
    return delegate.getParameterHandler();
  }
}

查看上面的源码,我们可以发现RoutingStatementHandler根据不同的Statement类型持有相应的StatementHandler,RoutingStatementHandler的所有函数都是依赖于具体的StatementHandler的具体函数来实现的。这里相当于一个什么设计模式呢?相当于一个策略模式,而RoutingStatementHandler就相当于一个策略容器,StatemetnHandler是抽象策略类,而BaseStatementHandler的子类SimpleStatementHandler、PreparedStatementHandler和CallableStatementHandler就是具体策略类。

接下来,我们来看一下StatemetnHandler接口的各个实现类的具体作用。

(1)RoutingStatementHandler:这是一个封装类,不提供任何具体的实现,只是根据不同的Executor来创建不同的StatementHandler,然后依赖于具体的statementHandler来实现不同的方法。其实这就相当于一个策略模式的策略容器。
(2)SimpleStatementHandler:这个类对应于JDBC的Statement对象,用于没有预编译的SQL的运行。
(3)PreparedStatementHandler :这个用于预编译参数的SQL运行。
(4)CallableStatementHandler :用于存储过程的调用。

接下来我们来看一看StatementHandler各个函数的作用及部分函数的逻辑。

4 BaseStatementHandler

BaseStatementHandler里面实现的函数其实就是做好准备工作,我们来看prepare函数的逻辑。

    /**
     * 传入Connection,创建并初始化Statement
     */
    @Override
    public Statement prepare(Connection connection) throws SQLException {
        ErrorContext.instance().sql(boundSql.getSql());
        Statement statement = null;
        try {

            //初始化statement		
            statement = instantiateStatement(connection);

            //设置查询超时时间
            setStatementTimeout(statement);

            //设置每次允许传递到数据库的查询语句条数
            setFetchSize(statement);
            return statement;
        } catch (SQLException e) {

            //如果发生异常则关闭Statement		
            closeStatement(statement);
            throw e;
        } catch (Exception e) {

            //如果发生异常则关闭Statement	
            closeStatement(statement);
            throw new ExecutorException("Error preparing statement.  Cause: " + e, e);
        }
    }

针对具体的StatemetnHandler我们来看一下SimpleStatementHandler的实现就行,至于其余的StatementHandler函数的实现其实就是调用不同的Statement(StatementImpl、PreparedStatement、CallableStatement)来实现不同类型的数据库操作而已。

5 SimpleStatementHandler

(1)update函数

    @Override
    public int update(Statement statement) throws SQLException {
        String sql = boundSql.getSql();
        Object parameterObject = boundSql.getParameterObject();
        KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
        int rows;

        //针对不同的主键生成器采用不同的主键生成策略
        if (keyGenerator instanceof Jdbc3KeyGenerator) {

            //指定sql语句	
            statement.execute(sql, Statement.RETURN_GENERATED_KEYS);

            //获取影响的记录数
            rows = statement.getUpdateCount();
            keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
        } else if (keyGenerator instanceof SelectKeyGenerator) {
            statement.execute(sql);
            rows = statement.getUpdateCount();
            keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
        } else {
            statement.execute(sql);
            rows = statement.getUpdateCount();
        }
        return rows;
    }

(2)batch函数

@Override
public void batch(Statement statement) throws SQLException {
    String sql = boundSql.getSql();
	
    //执行statement的批量添加
    statement.addBatch(sql);
}

(3)query函数

@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    String sql = boundSql.getSql();
    statement.execute(sql);
	
    //这里需要使用到ResultHandler来处理查询结果
    return resultSetHandler.<E>handleResultSets(statement);
}

(4)instantiateStatement函数

@Override
protected Statement instantiateStatement(Connection connection) throws SQLException {
	
    //使用Connection的createStatement函数创建Statement对象
    if (mappedStatement.getResultSetType() != null) {
        return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    } else {
        return connection.createStatement();
    }
}

(5)parameterize函数

//参数预处理,只有PrepareStatementHandler类才有这个函数的具体实现
@Override
public void parameterize(Statement statement) throws SQLException {
    // N/A
}

上面的类容就是我们对StatementHandler的分析,接下来我们将要继续分析Mybatis绑定参数和处理执行结果的Handler,ParameterHandler和ResultHandler。欢迎交流。

猜你喜欢

转载自blog.csdn.net/ONROAD0612/article/details/83575584
今日推荐