SelectKey标签在mybatis中可以配置成在主sql执行之前和执行之后两种时机进行执行。

mybatis执行sql时一次会涉及到这些对象

sqlSession-->Executor-->StatementHandler

其中selectKey的处理就是在StatementHandler中进行的

一、在主sql执行之前执行

BaseStatementHandler的构造方法中会检查是否需要处理selectKey的执行,这就是在主sql执行之前执行

protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    this.configuration = mappedStatement.getConfiguration();
    this.executor = executor;
    this.mappedStatement = mappedStatement;
    this.rowBounds = rowBounds;

    this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
    this.objectFactory = configuration.getObjectFactory();

    if (boundSql == null) { 
      //这块就是在处理主sql之前执行selectKey
      generateKeys(parameterObject);
      boundSql = mappedStatement.getBoundSql(parameterObject);
    }

    this.boundSql = boundSql;

    this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
    this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
  }

protected void generateKeys(Object parameter) {
    KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
    ErrorContext.instance().store();
    //这块是具体的方法,keyGenerator是一个接口,当使用selectKey标签时,对应的实现类是
    // SelectKeyGenerator
    keyGenerator.processBefore(executor, mappedStatement, null, parameter);
    ErrorContext.instance().recall();
  }

二、在主sql执行之后执行

StatementHandler是一个接口,BaseStatementHandler是一个公共实现类,具体的数据库处理逻辑是在其子类中实现的。我们以PreparedStatementHandler举例,insert语句最终会通过statementHandler中的 update方法来执行

public int update(Statement statement) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    //这里是用PreparedStatement执行sql语句
    ps.execute();
    int rows = ps.getUpdateCount();
    Object parameterObject = boundSql.getParameterObject();
    KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
    // 这里就是在处理主sql之后执行selectKey标签
    keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
    return rows;
}