Spring集成Mybatis源码分析(四)-Mapper方法调用流程

接第二篇中MapperProxy方法的invoke方法讲起

MapperProxy

这个类是每一个Mapper的动态代理对象对应的InvocationHandler,当调用代理对象的方法时,都会调用到该方法的invoke方法,并传入代理对象,方法,参数。
首先判断当前方法是不是继承自Object的方法,如果是,直接执行原方法。否则生成一个MapperMethod对象,用来执行代理方法。而这个类就是执行增删改查的关键类。

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if (Object.class.equals(method.getDeclaringClass())) {
        try {
            return method.invoke(this, args);
        } catch (Throwable t) {
            throw ExceptionUtil.unwrapThrowable(t);
        }
    }
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    return mapperMethod.execute(sqlSession, args);
}

private MapperMethod cachedMapperMethod(Method method) {
    MapperMethod mapperMethod = methodCache.get(method);
    if (mapperMethod == null) {
        mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
        methodCache.put(method, mapperMethod);
    }
    return mapperMethod;
}

MapperMethod
// SQL
private final SqlCommand command;
// 方法签名
private final MethodSignature method;
public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
    this.command = new SqlCommand(config, mapperInterface, method);
    this.method = new MethodSignature(config, method);
}

SqlCommand
  • 查找Statement
public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {
    String statementName = mapperInterface.getName() + "." + method.getName();
    MappedStatement ms = null;
    // 根据之前解析过的XML或者接口是否已经有该statement了
    if (configuration.hasStatement(statementName)) {
        ms = configuration.getMappedStatement(statementName);
    // 如果是继承的接口上的方法,判断以父接口名 + 方法名是否存在statement
    } else if (!mapperInterface.equals(method.getDeclaringClass())) { // issue #35
        String parentStatementName = method.getDeclaringClass().getName() + "." + method.getName();
        if (configuration.hasStatement(parentStatementName)) {
            ms = configuration.getMappedStatement(parentStatementName);
        }
    }
    
    // 如果没找到,判断是否是flush,如果有表示该方法仅用于刷新缓存
    if (ms == null) {
        if(method.getAnnotation(Flush.class) != null){
            name = null;
            type = SqlCommandType.FLUSH;
        } else {
            throw new BindingException("Invalid bound statement (not found): " + statementName);
        }
    } else {
        name = ms.getId();
        type = ms.getSqlCommandType();
        if (type == SqlCommandType.UNKNOWN) {
            throw new BindingException("Unknown execution method for: " + name);
        }
    }
}

MethodSignature
  • 分析方法,解析出方法签名对象
public MethodSignature(Configuration configuration, Method method) {
    // 返回类型
    this.returnType = method.getReturnType();
    // 是否返回void
    this.returnsVoid = void.class.equals(this.returnType);
    // 是否返回多个
    this.returnsMany = (configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray());
    // 获取@MapKey的值
    this.mapKey = getMapKey(method);
    // 是否返回Map
    this.returnsMap = (this.mapKey != null);
    // 是否有标注有@Params的参数
    this.hasNamedParameters = hasNamedParams(method);
    // 参数中RowBounds的索引
    this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
    // 参数中ResultHandler的索引
    this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);
    // 获取参数名称列表,用于后续替换SQL中的参数,逻辑为如果标注了@Params,就使用@Params的值,如果没有就使用参数所在下标
    this.params = Collections.unmodifiableSortedMap(getParams(method, this.hasNamedParameters));
}

执行execute方法
  • 根据不同的statement获得的不通SqlCommandType,执行不同的逻辑
public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    if (SqlCommandType.INSERT == command.getType()) {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.insert(command.getName(), param));
    } else if (SqlCommandType.UPDATE == command.getType()) {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.update(command.getName(), param));
    } else if (SqlCommandType.DELETE == command.getType()) {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.delete(command.getName(), param));
    } else if (SqlCommandType.SELECT == command.getType()) {
        if (method.returnsVoid() && method.hasResultHandler()) {
            executeWithResultHandler(sqlSession, args);
            result = null;
        } else if (method.returnsMany()) {
            result = executeForMany(sqlSession, args);
        } else if (method.returnsMap()) {
            result = executeForMap(sqlSession, args);
        } else {
            Object param = method.convertArgsToSqlCommandParam(args);
            result = sqlSession.selectOne(command.getName(), param);
        }
    } else if (SqlCommandType.FLUSH == command.getType()) {
        result = sqlSession.flushStatements();
    } else {
        throw new BindingException("Unknown execution method for: " + command.getName());
    }
    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
        throw new BindingException("Mapper method '" + command.getName() 
                                   + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
    }
    return result;
}
  • 先来分析SELECT方法,分为几种情况
    • 无返回值且参数中有ResultHandler,执行executeWithResultHandler(sqlSession, args);
private void executeWithResultHandler(SqlSession sqlSession, Object[] args) {
    MappedStatement ms = sqlSession.getConfiguration().getMappedStatement(command.getName());
    if (void.class.equals(ms.getResultMaps().get(0).getType())) {
        throw new BindingException("method " + command.getName() 
                                   + " needs either a @ResultMap annotation, a @ResultType annotation," 
                                   + " or a resultType attribute in XML so a ResultHandler can be used as a parameter.");
    }
    Object param = method.convertArgsToSqlCommandParam(args);
    if (method.hasRowBounds()) {
        RowBounds rowBounds = method.extractRowBounds(args);
        sqlSession.select(command.getName(), param, rowBounds, method.extractResultHandler(args));
    } else {
        sqlSession.select(command.getName(), param, method.extractResultHandler(args));
    }
}
     - 转换参数值,将传入的参数进行转换
        - 如果没有参数,返回null
        - 如果有一个参数并且没有@Params注解的参数,返回第一个参数值
        - 如果有多个参数,新建ParamMap对象,首先按之前方法签名中解析到的paramName作为key,参数值对应参数下标获取参数值作为value,同时再新增param1,param2按顺序作为key,再存入一份。即未来可以通过“0,1,2”或者“param1,param2, param3”或者“actualParamName1,actualParamName2,actualParamName3”来获取到参数值替换Sql中的参数名称
public Object convertArgsToSqlCommandParam(Object[] args) {
    final int paramCount = params.size();
    if (args == null || paramCount == 0) {
        return null;
    } else if (!hasNamedParameters && paramCount == 1) {
        return args[params.keySet().iterator().next().intValue()];
    } else {
        final Map<String, Object> param = new ParamMap<Object>();
        int i = 0;
        for (Map.Entry<Integer, String> entry : params.entrySet()) {
            param.put(entry.getValue(), args[entry.getKey().intValue()]);
            // issue #71, add param names as param1, param2...but ensure backward compatibility
            final String genericParamName = "param" + String.valueOf(i + 1);
            if (!param.containsKey(genericParamName)) {
                param.put(genericParamName, args[entry.getKey()]);
            }
            i++;
        }
        return param;
    }
}
     - 执行SqlSession的select方法,分为有RowBounds和无RowBounds参数两种,这里的sqlSession目前的实现是SqlSessionTemplate,是在自动注入MapperFactoryBean的时候注入的,实际就是调用了sqlSessionTemplate的select方法
if (method.hasRowBounds()) {
    RowBounds rowBounds = method.extractRowBounds(args);
    sqlSession.select(command.getName(), param, rowBounds, method.extractResultHandler(args));
} else {
    sqlSession.select(command.getName(), param, method.extractResultHandler(args));
}
     - SqlSesstionTemplate是调用了他的一个属性sqlSessionProxy动态代理对象的select方法,这个对象在实例化SqlSessionTemplate时创建,是一个JDK动态代理对象,该代理对象传入的InvocationHandler是SqlSessionInterceptor,
public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
    this.sqlSessionProxy.select(statement, parameter, rowBounds, handler);
}
     - SqlSessionInterceptor这个类的invoke方法拦截select方法,在这个方法中就会去获取session,并执行目标方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    // 获取session,通过Spring提供的TransactionSynchronizationManager获取当前线程是否绑定过一个SqlSessionHolder,如果绑定过,则可以直接重用原Session,如果没有,重新打开一个新的session
    // 这里最终会获取到一个DefaultSqlSession
    SqlSession sqlSession = getSqlSession(
        SqlSessionTemplate.this.sqlSessionFactory,
        SqlSessionTemplate.this.executorType,
        SqlSessionTemplate.this.exceptionTranslator);
    try {
        // 执行目标方法,跳转到DefaultSqlSession的方法中
        Object result = method.invoke(sqlSession, args);
        // 如果不是Spring管理的session,则强制提交
        if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
            // force commit even on non-dirty sessions because some databases require
            // a commit/rollback before calling close()
            sqlSession.commit(true);
        }
        return result;
    } catch (Throwable t) {
        Throwable unwrapped = unwrapThrowable(t);
        if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
            // release the connection to avoid a deadlock if the translator is no loaded. See issue #22
            // 关闭session,释放资源
            closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
            sqlSession = null;
            Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
            if (translated != null) {
                unwrapped = translated;
            }
        }
        throw unwrapped;
    } finally {
        // 关闭session,释放资源
        if (sqlSession != null) {
            closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
        }
    }
}
     - 获取DefaultSqlSession
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
        final Environment environment = configuration.getEnvironment();
        // 获取到之前创建的事务工厂,默认为SpringManagedTransactionFactory
        final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
        // 创建事务,默认为SpringManagedTransaction
        tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
        // 创建执行器,默认为SIMPLE
        final Executor executor = configuration.newExecutor(tx, execType);
        // 返回DefaultSqlSession
        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();
    }
}

// 该方法在Configuration中
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);
    }
    // 如果开启了缓存,其实默认是开启的,装饰器模式装饰一个CachingExecutor
    if (cacheEnabled) {
      executor = new CachingExecutor(executor);
    }
    // 为执行器增强插件功能
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
  }
     - DefaultSqlSession.select方法
@Override
public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
    try {
        MappedStatement ms = configuration.getMappedStatement(statement);
        executor.query(ms, wrapCollection(parameter), rowBounds, handler);
    } catch (Exception e) {
        throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
        ErrorContext.instance().reset();
    }
}
     - 默认调用CachingExecutor的query方法
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    BoundSql boundSql = ms.getBoundSql(parameterObject);
    CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
    return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
        - 利用MappedStatement获取BoundSql,
public BoundSql getBoundSql(Object parameterObject) {
    BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
    if (parameterMappings == null || parameterMappings.isEmpty()) {
        boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);
    }

    // check for nested result maps in parameter mappings (issue #30)
    for (ParameterMapping pm : boundSql.getParameterMappings()) {
        String rmId = pm.getResultMapId();
        if (rmId != null) {
            ResultMap rm = configuration.getResultMap(rmId);
            if (rm != null) {
                hasNestedResultMaps |= rm.hasNestedResultMaps();
            }
        }
    }

    return boundSql;
}
        - 继续调用DynamicSqlSource的getBoundSql方法
public BoundSql getBoundSql(Object parameterObject) {
    DynamicContext context = new DynamicContext(configuration, parameterObject);
    // 这里会将SQL中的${}替换为实际传入的参数的值
    rootSqlNode.apply(context);
    SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
    Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
    /**
    	parse方法[代码如下]中替换了#{param1}的参数为?,并记录下了ParameterMapping
        ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType, additionalParameters);
        GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);
        String sql = parser.parse(originalSql);
        return new StaticSqlSource(configuration, sql, handler.getParameterMappings());
    */
    SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
    // 前面所有的都是在根据参数于条件判断等获取到真正的Sql,即由DynamicSqlSource转换成StaticSqlSource,去除了像<choose>,<if>这之类的条件判断,替换了#{param1}这样的参数
    // 接下来就是调用StaticSqlSource进行参数替换
    BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
    for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) {
      boundSql.setAdditionalParameter(entry.getKey(), entry.getValue());
    }
    return boundSql;
  }
     - 利用MappesStatement,parameter,rowBounds,以及上面获取到的BoundSql创建缓存的Key
     - 调用CachingExecutor的query查询数据,这个类是SimpleExecutor的装饰器,先查询是否有缓存,如果有,直接返回
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
      throws SQLException {
    Cache cache = ms.getCache();
    if (cache != null) {
        // 判断是否需要刷新缓存,这个方法中会给原来的Cache再装饰一层TransactionCache,调用clear方法,会将其一个clearOnCommit标识改为true,一旦被标识为true之后,后续再从缓存中获取时,直接返回null,
        // 如果有事务提交,也会直接将所有缓存先清空,再flush
      flushCacheIfRequired(ms);
      if (ms.isUseCache() && resultHandler == null) {
        ensureNoOutParams(ms, parameterObject, boundSql);
        @SuppressWarnings("unchecked")
        List<E> list = (List<E>) tcm.getObject(cache, key);
          // 有Cache,但Cache中没有缓存数据,直接调用SimpleExecutor去查询
        if (list == null) {
          list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
          tcm.putObject(cache, key, list); // issue #578 and #116
        }
        return list;
      }
    }
    // 没有设置缓存直接查
    return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }
     - BaseExecutor,SimpleExecutor继承自BaseExecutor,query由BaseExecutor实现
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
    if (closed) {
        throw new ExecutorException("Executor was closed.");
    }
    // 需要刷新缓存的化,清除BaseExecutor中的PerpetualCache中的缓存,注意,这里的PerpetualCache和之前解析<cache>时创建的不同,这里的是一定会生成的本地缓存,
    // 而之前那个是二级缓存,只有在cacheEnabled配置为true并且Mapper.xml中配置了<cache>才会生效
    // 这里的本地缓存生命周期很短,因为这个Executor实际上是创建DefaultSqlSession是新建的一个属性,因此属于session独享的,一旦session关闭后,其他session是获取不到该session下的本地缓存的
    if (queryStack == 0 && ms.isFlushCacheRequired()) {
        clearLocalCache();
    }
    List<E> list;
    try {
        queryStack++;
        list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
        // 本地缓存有
        if (list != null) {
            handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
        } else {
            // 本地缓存未查询到数据则从数据库去查
            list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
        }
    } finally {
        queryStack--;
    }
    if (queryStack == 0) {
        for (DeferredLoad deferredLoad : deferredLoads) {
            deferredLoad.load();
        }
        // issue #601
        deferredLoads.clear();
        // 设置了本地缓存作用域为STATEMENT的话,每次都清除本地缓存
        if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
            // issue #482
            clearLocalCache();
        }
    }
    return list;
}
     - 从数据库查会通过Configuration新建一个重要的组件叫StatementHandler,默认实现为PreparedStatementHandler,可通过在Mapper xml中设置statementType属性修改,这里插件又排上用场了,可以为StatementHandler装饰插件,不仅是在这里,在新建RoutingStatementHandler这个类时,会根据statementType选择不同的statementHandler,比如在new默认的PreparedStatementHandler时,会调用父类BaseStatementHandler的构造方法,在这个方法中还会调用configuration.newParameterHandler,configuration.newResultSetHandler,这两个方法同样会为ParameterHandler,和ResultSetHandler添加插件功能。因此至此,我们直到了为Mabatis可以在4个地方为其增加插件功能。总结如下:
        - Executor:执行器,可通过增强他改变查询,本地缓存,提交/回滚等功能的变更
        - StatementHandler:可改变sql的生成,比如在这类拦截prepare,然后修改sql,实现分页
        - ResultSetHandler:可以改变返回结果的生成方式
        - ParameterHandler: 参数处理器,可改变参数赋值的行为
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;
}

public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
    ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
    parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
    return parameterHandler;
}

public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
                                            ResultHandler resultHandler, BoundSql boundSql) {
    ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
    resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
    return resultSetHandler;
}
     - 然后开始构造PreparedStatement
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    // 获取数据库连接
    Connection connection = getConnection(statementLog);
    // 生成PreparedStatement,这里直接把代码copy过来
    /**
     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) {
          closeStatement(statement);
          throw e;
        } catch (Exception e) {
          closeStatement(statement);
          throw new ExecutorException("Error preparing statement.  Cause: " + e, e);
        }
      }
    */
    stmt = handler.prepare(connection);
    // 为PreparedStatement中的? 复制,主要逻辑是根据ParameterMapping获取到参数的下标,值以及类型处理器,通过不同的类型处理器对?赋值
    handler.parameterize(stmt);
    return stmt;
}
     - 调用ResultSetHandler的handleResultSets方法处理返回结果
public List<Object> handleResultSets(Statement stmt) throws SQLException {
    ErrorContext.instance().activity("handling results").object(mappedStatement.getId());

    final List<Object> multipleResults = new ArrayList<Object>();

    int resultSetCount = 0;
    // ResultSet的包装类
    ResultSetWrapper rsw = getFirstResultSet(stmt);

    // 获取之前定义的ResultMap
    List<ResultMap> resultMaps = mappedStatement.getResultMaps();
    int resultMapCount = resultMaps.size();
    // 验证是否获取到了结果,但resultMap却未指定
    validateResultMapsCount(rsw, resultMapCount);
    // 
    while (rsw != null && resultMapCount > resultSetCount) {
        ResultMap resultMap = resultMaps.get(resultSetCount);
        handleResultSet(rsw, resultMap, multipleResults, null);
        rsw = getNextResultSet(stmt);
        cleanUpAfterHandlingResultSet();
        resultSetCount++;
    }

    String[] resultSets = mappedStatement.getResulSets();
    if (resultSets != null) {
        while (rsw != null && resultSetCount < resultSets.length) {
            ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
            if (parentMapping != null) {
                String nestedResultMapId = parentMapping.getNestedResultMapId();
                ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
                handleResultSet(rsw, resultMap, null, parentMapping);
            }
            rsw = getNextResultSet(stmt);
            cleanUpAfterHandlingResultSet();
            resultSetCount++;
        }
    }

    return collapseSingleResultList(multipleResults);
}
        - handleResultSet方法,获取ResultSet中的值,根据之前配置的映射或者对象属性,新建并逐层返回
 private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
      throws SQLException {
     DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();
     // RowBounds逻辑分页,跳过不要的行
     skipRows(rsw.getResultSet(), rowBounds);
     while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
         // 鉴别器,很少用
         ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
         // 创建对象,并根据ResultMap映射为属性赋值,首先赋值未显式指定<property>的属性,然后指定了<property>的属性
         Object rowValue = getRowValue(rsw, discriminatedResultMap);
         storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
     }
 }
     - 至此executeWithResultHandler主流程基本就结束了,以下三种查询的流程基本一致,只是将查询到的list做了不同的封装处理,如executeMany将list进行指定对象的封装,executeForMap采用DefaultMapResultHandler将对象转换成map
  - 返回集合,执行executeForMany(sqlSession, args);
  - 返回Map,执行executeForMap(sqlSession, args);
  - 其他,直接转换参数,调用sqlSession.selectOne()方法
  • 分析了Select方法,再来看一个INSERT方法
    • 同样的首先先转换可用参数名,如param1,param2等等
if (SqlCommandType.INSERT == command.getType()) {
    Object param = method.convertArgsToSqlCommandParam(args);
    result = rowCountResult(sqlSession.insert(command.getName(), param));
}
  - 直接调用insert方法,insert方法在DefaultSqlSession中又调用了update方法
public int update(String statement, Object parameter) {
    try {
        dirty = true;
        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();
    }
}
  - 将集合类对象转换成MapperXml中能识别的collection,list,或者array
private Object wrapCollection(final Object object) {
    if (object instanceof Collection) {
        StrictMap<Object> map = new StrictMap<Object>();
        map.put("collection", object);
        if (object instanceof List) {
            map.put("list", object);
        }
        return map;
    } else if (object != null && object.getClass().isArray()) {
        StrictMap<Object> map = new StrictMap<Object>();
        map.put("array", object);
        return map;
    }
    return object;
}
  - 调用CachingExecutor,同样的,和query操作一样,如果开启了二级缓存,首先判断是否需要刷新缓存,然后调用BaseExecutor的update方法
public int update(MappedStatement ms, Object parameterObject) throws SQLException {
    flushCacheIfRequired(ms);
    return delegate.update(ms, parameterObject);
}
  - 事务类操作首先都刷新本地缓存, 然后调用SimpleExecutor的doUpdate方法
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);
}
  - 和query一样,默认新建PreparedStatementHandler处理器,然后替换其中的?赋值,新建PreparedStatement, 最后执行PrepareStatementHandler的update方法并返回,注意,这里在new PreparedStatementHandler同样会触发父类BaseStatementHandler的构造方法,这里会执行generateKeys(parameterObject)方法,目的是在执行真正的插入语句之前,先执行SelectKeyGenerator的方法,生成主键。
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
    Statement stmt = null;
    try {
        Configuration configuration = ms.getConfiguration();
        StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
        stmt = prepareStatement(handler, ms.getStatementLog());
        return handler.update(stmt);
    } finally {
        closeStatement(stmt);
    }
}
  - 执行insert语句,并返回操作成功的数量,如果指定了需要使用useGeneratedKeys,或这个在Mapper XML中使用了<selectKey>标签,这个会在最开始解析XML时创建,见上一篇文章,那么此处需要执行查询语句,分别会调用Jdbc3KeyGenerator和SelectKeyGenerator的processAfter方法为传入的参数的主键属性赋值。
public int update(Statement statement) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();
    int rows = ps.getUpdateCount();
    Object parameterObject = boundSql.getParameterObject();
    KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
    keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
    return rows;
}
  - insert的流程比较简单,大致就分析到这里吧。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值