第六章-Mybatis源码解析-StatementHandler语句处理和执行(一)

第五章中分别有讲到select和insert的执行流程,并分别都会走到 SimpleExecutor 类的 doQuery 和 doUpdate 方法,先贴出这两个方法

**doQuery **

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();
        // doQuery 和 doUpdate 都有这行代码,作用是创建语句处理器,看章节`6.1`
        StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
        // 预编译语句,有过jdbc开发经验的就了解了,从这里开始,就是jdbc的操作封装了,看章节`6.2`
        stmt = prepareStatement(handler, ms.getStatementLog());
        // 查询就执行 StatementHandler 的 query 方法,看章节`6.3`
        return handler.query(stmt, resultHandler);
    } finally {
        closeStatement(stmt);
    }
}

**doUpdate **

public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
    Statement stmt = null;
    try {
        Configuration configuration = ms.getConfiguration();
        // doQuery 和 doUpdate 都有这行代码,作用是创建语句处理器,看章节`6.1`
        StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
        // 预编译语句,看章节`6.2`
        stmt = prepareStatement(handler, ms.getStatementLog());
        // 更新(insert|update|delete)就执行 StatementHandler 的 update 方法,看章节`6.4`
        return handler.update(stmt);
    } finally {
        closeStatement(stmt);
    }
}

6.1 newStatementHandler创建语句处理器

configuration.newStatementHandler

public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    // 进一步创建RoutingStatementHandler,往下走
    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
    // 执行插件链
    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
    return statementHandler;
}

new RoutingStatementHandler

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());
    }
}

SimpleStatementHandler、PreparedStatementHandler、CallableStatementHandler 三个类各自都继承 BaseStatementHandler 类,并且它们的构造函数中都没有做其他处理,都是直接super调用父类构造函数,那直接看父类 BaseStatementHandler 的构造函数实现。

BaseStatementHandler构造函数

protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    // 下面4行,都是赋值
    this.configuration = mappedStatement.getConfiguration();
    this.executor = executor;
    this.mappedStatement = mappedStatement;
    this.rowBounds = rowBounds;
    // 下面2行,分别拿到类型处理器和对象工厂
    this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
    this.objectFactory = configuration.getObjectFactory();

    if (boundSql == null) { // issue #435, get the key before calculating the statement
        // 这一行是针对语句中,有对 selectKey设置,并且是执行前的操作时,才要处理
        generateKeys(parameterObject);
        // 获取boundSql,前面章节`5.1.1.1-1`有讲过,可以回头去看下
        boundSql = mappedStatement.getBoundSql(parameterObject);
    }
    // 赋值
    this.boundSql = boundSql;
    // 创建参数处理器,比较简单,只提供了设置和获取参数两种操作,内部也有对插件链的执行
    this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
    // 创建结果集处理器,细节待`第七章`中讲
    this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}

6.2 prepareStatement预编译语句

SimpleExecutor.prepareStatement 方法

private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    // 拿到链接,这里可能读者要问,connection 哪里来的,请回头看看章节`4.3`
    Connection connection = getConnection(statementLog);
    // 这一步会走到 BaseStatementHandler.prepare 方法,看章节`6.2.1`
    stmt = handler.prepare(connection, transaction.getTimeout());
    // 参数化,这一步调的是 RoutingStatementHandler.parameterize 方法,看章节`6.2.2`
    handler.parameterize(stmt);
    return stmt;
}

6.2.1 BaseStatementHandler.prepare

public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
    ErrorContext.instance().sql(boundSql.getSql());
    Statement statement = null;
    try {
        // instantiateStatement 方法是一个 protected abstract 的抽象方法,由子类 SimpleStatementHandler、PreparedStatementHandler、CallableStatementHandler 各自实现,章节`6.2.1.1` 至 章节`6.2.1.3` 分别讲述三个子类的实现
        statement = instantiateStatement(connection);
        // 拿到 statement 后,给它设置超时时间
        setStatementTimeout(statement, transactionTimeout);
        // 设置获取结果的大小:fetchSize	这是一个给驱动的建议值,尝试让驱动程序每次批量返回的结果行数等于这个设置值。 默认值为未设置(unset)(依赖驱动)
        setFetchSize(statement);
        return statement;
    } catch (SQLException e) {
        closeStatement(statement);
        throw e;
    } catch (Exception e) {
        closeStatement(statement);
        throw new ExecutorException("Error preparing statement.  Cause: " + e, e);
    }
}

protected void setStatementTimeout(Statement stmt, Integer transactionTimeout) throws SQLException {
    Integer queryTimeout = null;
    if (mappedStatement.getTimeout() != null) {
        queryTimeout = mappedStatement.getTimeout();
    } else if (configuration.getDefaultStatementTimeout() != null) {
        queryTimeout = configuration.getDefaultStatementTimeout();
    }
    if (queryTimeout != null) {
        stmt.setQueryTimeout(queryTimeout);
    }
    StatementUtil.applyTransactionTimeout(stmt, queryTimeout, transactionTimeout);
}
6.2.1.1 SimpleStatementHandler.instantiateStatement
protected Statement instantiateStatement(Connection connection) throws SQLException {
    /* 这里涉及一个知识点:结果集类型(ResultSetType),官网描述:
    FORWARD_ONLY,SCROLL_SENSITIVE, SCROLL_INSENSITIVE 或 DEFAULT(等价于 unset) 中的一个,默认值为 unset (依赖数据库驱动)
    FORWARD_ONLY:结果集只能单方向向前遍历
    SCROLL_SENSITIVE:结果集可随意遍历并修改
    SCROLL_INSENSITIVE:结果集可随意遍历,但不可修改
    DEFAULT:未设置(依赖数据库驱动)
    */
    if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
        // 这一行就是写jdbc时要用的,创建 Statement
        return connection.createStatement();
    } else {
        // 根据结果集类型创建 Statement
        return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    }
}
6.2.1.2 PreparedStatementHandler.instantiateStatement
 protected Statement instantiateStatement(Connection connection) throws SQLException {
     String sql = boundSql.getSql();
     if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
         String[] keyColumnNames = mappedStatement.getKeyColumns();
         if (keyColumnNames == null) {
             return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
         } else {
             return connection.prepareStatement(sql, keyColumnNames);
         }
     } else if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
         // 直接看这里吧,熟悉的人都知道,这又是写jdbc时的代码
         return connection.prepareStatement(sql);
     } else {
         return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
     }
 }
6.2.1.3 CallableStatementHandler.instantiateStatement
protected Statement instantiateStatement(Connection connection) throws SQLException {
    String sql = boundSql.getSql();
    // 又是写jdbc时的代码
    if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
        return connection.prepareCall(sql);
    } else {
        return connection.prepareCall(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    }
}

6.2.2 RoutingStatementHandler.parameterize

 public void parameterize(Statement statement) throws SQLException {
     // 这里的 delegate 分别表示 SimpleStatementHandler、PreparedStatementHandler、CallableStatementHandler,所以又得分化成三种实现。SimpleStatementHandler 没有具体实现;CallableStatementHandler 关于存储过程的,由读者自行扩展;那么就剩下 PreparedStatementHandler 的实现了,其内部是调用的 DefaultParameterHandler.setParameters 方法,所以,直接讲这个方法
     delegate.parameterize(statement);
 }

DefaultParameterHandler.setParameters

public void setParameters(PreparedStatement ps) {
    ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
    // 从 boundSql 中取出参数映射列表 parameterMappings
    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
    if (parameterMappings != null) {
        // 有值,就遍历
        for (int i = 0; i < parameterMappings.size(); i++) {
            ParameterMapping parameterMapping = parameterMappings.get(i);
            // 参数必须是输入模式
            if (parameterMapping.getMode() != ParameterMode.OUT) {
                Object value;
                // 参数名
                String propertyName = parameterMapping.getProperty();
                // 针对 DynamicSqlSource 的额外参数(其实这个,可以自定义,比如定义成一个Map传参,但是定义的时候,要注意key只能是“_parameter”)
                if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
                    // 获得对应额外参数值
                    value = boundSql.getAdditionalParameter(propertyName);
                } else if (parameterObject == null) {
                    // 没有参数值,设Null
                    value = null;
                } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
                    // 类型处理器中,有对应的类型,直接赋值,关于类型处理器的描述,可以进入TypeHandlerRegistry类源码看一下就知道了
                    value = parameterObject;
                } else {
                    // 如果是普通对象,那就解析对象属性
                    MetaObject metaObject = configuration.newMetaObject(parameterObject);
                    value = metaObject.getValue(propertyName);
                }
                // 接下来就是java数据类型跟jdbc中类型的转换了
                TypeHandler typeHandler = parameterMapping.getTypeHandler();
                JdbcType jdbcType = parameterMapping.getJdbcType();
                if (value == null && jdbcType == null) {
                    jdbcType = configuration.getJdbcTypeForNull();
                }
                try {
                    // 给参数设置值,这一步就会将java类型的数据转换成jdbc类型的
                    typeHandler.setParameter(ps, i + 1, value, jdbcType);
                } catch (TypeException | SQLException e) {
                    throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
                }
            }
        }
    }
}

  • 9
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

多栖码农

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值