Analysis of selectKey source code in Mybatis

 

 Just answered a question such a question, mybatis can't return the primary key to increase the value normally.   Let's analyze the selectKey through the source code.

 

@Insert("insert into table2 (name) values(#{name})")
    @SelectKey(statement="call identity()", keyProperty="nameId", before=false, resultType=int.class)
    int insertTable2(Name name);

  

 

KeyGenerator interface

/**
 * key generator interface
 */
public interface KeyGenerator {
  //Execute selectKey before executing main SQL
  void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter);

  //Execute selectkey after main SQL execution
  void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter);

}

 

before specific execution time  

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) { // issue #435, get the key before calculating the statement
// // execute before
      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.processBefore(executor, mappedStatement, null, parameter);
    ErrorContext.instance().recall();
  }

  

  @Override
  public void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
    //Whether to execute before execution, if not, do not execute
    if (executeBefore) {
      processGeneratedKeys(executor, ms, parameter);
    }
  }

  after execution timing

 

@Override
  public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
    //If executeBefore is configured to false, execute
    if (!executeBefore) {
      processGeneratedKeys(executor, ms, parameter);
    }
  }

  

 Specific execution source code

private void processGeneratedKeys(Executor executor, MappedStatement ms, Object parameter) {
    try {
      //If parameter is not null and keyStatement is not null and keyStatement specifies keyProperties
      if (parameter != null && keyStatement != null && keyStatement.getKeyProperties() != null) {
        //Get keyProperties
        String[] keyProperties = keyStatement.getKeyProperties();
        //Get configuration information
        final Configuration configuration = ms.getConfiguration();
        //Get the parameter object metadata
        final MetaObject metaParam = configuration.newMetaObject(parameter);
        //In fact, it has been judged
        if (keyProperties != null) {
          //Create a new keyExecutor
          Executor keyExecutor = configuration.newExecutor(executor.getTransaction(), ExecutorType.SIMPLE);
          //Execute the query
          List<Object> values = keyExecutor.query(keyStatement, parameter, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
          //If the query result is 0, throw an exception
          if (values.size() == 0) {
            throw new ExecutorException("SelectKey returned no data.");            
          } else if (values.size() > 1) {//If there are more than 1 query result, an exception will be thrown
            throw new ExecutorException("SelectKey returned more than one value.");
          } else {//Only one result value is returned
            MetaObject metaResult = configuration.newMetaObject(values.get(0));
            //If the number of keyProperty is only 1
            if (keyProperties.length == 1) {
              //If the query result object has a getter method for this property
              if (metaResult.hasGetter(keyProperties[0])) {
                //Set the attribute value to param
                setValue(metaParam, keyProperties[0], metaResult.getValue(keyProperties[0]));
              } else {
                //If there is no getter method, set the current value to the property
                setValue(metaParam, keyProperties[0], values.get(0));
              }
            } else {//Process the scene of specifying multiple key attributes
              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);
    }
  }

  private void handleMultipleProperties(String[] keyProperties,
      MetaObject metaParam, MetaObject metaResult) {
    //Get all key columns
    String[] keyColumns = keyStatement.getKeyColumns();
      //if the key column does not exist
    if (keyColumns == null || keyColumns.length == 0) {
      //If the key column is not specified, use the configuration directly to the key property
      for (String keyProperty : keyProperties) {
        setValue(metaParam, keyProperty, metaResult.getValue(keyProperty));
      }
    } else {
      //There are key columns but the number is inconsistent
      if (keyColumns.length != keyProperties.length) {
        throw new ExecutorException("If SelectKey has key columns, the number must match the number of key properties.");
      }
      //The number is the same, requiring a one-to-one correspondence between keyColumn and keyProperty
      for (int i = 0; i < keyProperties.length; i++) {
        setValue(metaParam, keyProperties[i], metaResult.getValue(keyColumns[i]));
      }
    }
  }

  

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324721198&siteId=291194637