Mybatis源码解析之写流程

承接上文,我们继续来分析写操作: DefaultSqlSession:

public int insert(String statement, Object parameter) {
    return update(statement, parameter);
}

DefaultSqlSession:

public int update(String statement, Object parameter) {
    try {
        dirty = true;
        //获取MappedStatement
        MappedStatement ms = configuration.getMappedStatement(statement);
        /*包装集合类型的参数(分析查询流程时已经分析过),执行更新操作*/
        return executor.update(ms, wrapCollection(parameter));
    } catch (Exception e) {
        throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);
    } finally {
        ErrorContext.instance().reset();
    }
}

DefaultSqlSession:

public int delete(String statement, Object parameter) {
    return update(statement, parameter);
}

我们发现insert、update、delete三个方法最终都调用了同一个update方法。 CachingExecutor:

public int update(MappedStatement ms, Object parameterObject) throws SQLException {
    flushCacheIfRequired(ms); //如果需要,刷新缓存
    /*更新操作*/
    return delegate.update(ms, parameterObject);
}

Mybatis缓存我们会用单独的文章来分析。 BaseExecutor:

public int update(MappedStatement ms, Object parameter) throws SQLException {
    ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
    if (closed) {
        throw new ExecutorException("Executor was closed.");
    }
    clearLocalCache(); //清除本地缓存
    return doUpdate(ms, parameter); /*执行更新操作*/
}

SimpleExecutor:

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); //关闭Statement
    }
}

PreparedStatementHandler:

public int update(Statement statement) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute(); //执行sql命令
    int rows = ps.getUpdateCount(); //返回影响的行数
    Object parameterObject = boundSql.getParameterObject();
    KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
    /*KeyGenerator后置处理(前置处理在创建StatementHandler时应用)*/
    keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
    return rows;
}

我们以SelectKeyGenerator来分析KeyGenerator的后置处理: SelectKeyGenerator:

public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
    if (!executeBefore) { //如果不是前置处理
        /*处理生成的key*/
        processGeneratedKeys(executor, ms, parameter);
    }
}

分析之前我们可以先回想一下

<selectkey/>

标签的应用,有助于理解下面的处理过程。 SelectKeyGenerator:

private void processGeneratedKeys(Executor executor, MappedStatement ms, Object parameter) {
    try {
        if (parameter != null && keyStatement != null && keyStatement.getKeyProperties() != null) {
            String[] keyProperties = keyStatement.getKeyProperties(); //获取配置的目标属性
            final Configuration configuration = ms.getConfiguration();
            final MetaObject metaParam = configuration.newMetaObject(parameter);
            if (keyProperties != null) {
                //新建执行器
                Executor keyExecutor = configuration.newExecutor(executor.getTransaction(), ExecutorType.SIMPLE);
                //执行查询
                List<Object> values = keyExecutor.query(keyStatement, parameter, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
                //返回结果集长度的校验
                if (values.size() == 0) {
                    throw new ExecutorException("SelectKey returned no data.");            
                } else if (values.size() > 1) {
                    throw new ExecutorException("SelectKey returned more than one value.");
                } else {
                    MetaObject metaResult = configuration.newMetaObject(values.get(0));
                    //如果只设置了单个目标属性直接赋值
                    if (keyProperties.length == 1) {
                        if (metaResult.hasGetter(keyProperties[0])) {
                            setValue(metaParam, keyProperties[0], metaResult.getValue(keyProperties[0]));
                        } else {
                            setValue(metaParam, keyProperties[0], values.get(0));
                        }
                    } else {
                        /*设置多个目标属性的处理*/
                        handleMultipleProperties(keyProperties, metaParam, metaResult);
                    }
                }
            }
        }
    } catch (ExecutorException e) {
        throw e;
    } catch (Exception e) {
        throw new ExecutorException("Error selecting key or setting result to parameter object. Cause: " + e, e);
    }
}

SelectKeyGenerator:

private void handleMultipleProperties(String[] keyProperties,
    MetaObject metaParam, MetaObject metaResult) {
    String[] keyColumns = keyStatement.getKeyColumns();
    if (keyColumns == null || keyColumns.length == 0) {
        //没有指定具体的列,直接使用属性名称赋值
        for (String keyProperty : keyProperties) {
            setValue(metaParam, keyProperty, metaResult.getValue(keyProperty));
        }
    } else {
        //指定列的数量与属性的数量不相等抛出异常
        if (keyColumns.length != keyProperties.length) {
            throw new ExecutorException("If SelectKey has key columns, the number must match the number of key properties.");
        }
        for (int i = 0; i < keyProperties.length; i++) {
            //使用列名赋值
            setValue(metaParam, keyProperties[i], metaResult.getValue(keyColumns[i]));
        }
    }
}

最后是对返回影响行数的处理:

private Object rowCountResult(int rowCount) {
    final Object result;
    //根据方法返回值类型将影响行数转换成对应的类型
    if (method.returnsVoid()) {
        result = null;
    } else if (Integer.class.equals(method.getReturnType()) || Integer.TYPE.equals(method.getReturnType())) {
        result = rowCount;
    } else if (Long.class.equals(method.getReturnType()) || Long.TYPE.equals(method.getReturnType())) {
        result = (long)rowCount;
    } else if (Boolean.class.equals(method.getReturnType()) || Boolean.TYPE.equals(method.getReturnType())) {
        result = rowCount > 0;
    } else {
        throw new BindingException("Mapper method '" + command.getName() + "' has an unsupported return type: " + method.getReturnType());
    }
    return result;
}

到这里,Mybatis写操作的源码分析就完成了。

猜你喜欢

转载自blog.csdn.net/J_java1/article/details/83508845