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