Meituan Second: How does Mybatis execute a SQL command?

The Sql command in Mybatis is defined in the enumeration class SqlCommandType.

public enum SqlCommandType {
   
     UNKNOWN, INSERT, UPDATE, DELETE, SELECT, FLUSH;}

Below, we take a method in the Mapper interface as an example to see the complete flow of the execution of the Sql command.

public interface StudentMapper {
   
     List<Student> findAllStudents(Map<String, Object> map, RowBounds rowBounds, ResultSetHandler rh);  }

 

The parameters RowBounds and ResultSetHandler are optional parameters, representing the paging object and custom result set handler, which are generally not needed.
 

A complete Sql command, the complete flow chart of its execution is as follows:

 

(Made In Edrawmax)

 

For the above flowchart, if you have read the previous article, most of the objects are familiar to us. A diagram completely shows the execution process.

 

Features of MapperProxy:

1. Because the Mapper interface cannot be instantiated directly, the role of MapperProxy is to use the dynamic proxy function of the JDK to indirectly instantiate the proxy object of the Mapper. See the second part of the series.

2. Cache MapperMethod objects.

  private final Map<Method, MapperMethod> methodCache;  @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);  }
  // 缓存MapperMethod  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;  }

Functions of MapperMethod:

1. Analyze the methods of the Mapper interface and encapsulate them into a MapperMethod object.

2. Correctly route the Sql command to the appropriate SqlSession method.

public class MapperMethod {
   
   
  // 保存了Sql命令的类型和键id  private final SqlCommand command;  // 保存了Mapper接口方法的解析信息  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);  }
  // 根据解析结果,路由到恰当的SqlSession方法上  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;  }  // ...

 

org.apache.ibatis.binding.MapperMethod.SqlCommand。
public static class SqlCommand {

    // full id, 通过它可以找到MappedStatement    private final String name;    private final SqlCommandType type;// ...

org.apache.ibatis.binding.MapperMethod.MethodSignature。

  public static class MethodSignature {
   
       private final boolean returnsMany;    private final boolean returnsMap;    private final boolean returnsVoid;    private final Class<?> returnType;    private final String mapKey;    private final Integer resultHandlerIndex;    private final Integer rowBoundsIndex;    private final SortedMap<Integer, String> params;    private final boolean hasNamedParameters;
    public MethodSignature(Configuration configuration, Method method) {
   
         this.returnType = method.getReturnType();      this.returnsVoid = void.class.equals(this.returnType);      this.returnsMany = (configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray());      this.mapKey = getMapKey(method);      this.returnsMap = (this.mapKey != null);      this.hasNamedParameters = hasNamedParams(method);      // 分页参数      this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);      // 自定义ResultHandler      this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);      this.params = Collections.unmodifiableSortedMap(getParams(method, this.hasNamedParameters));    }

The above is a supplementary description of MapperMethod.

The focus of this section is the complete execution flow chart of the Sq1 command above. If you do not use the Mapper interface to call, but directly call the method of Sq1Session, then the flowchart can start from the place of Sq1Session, and the subsequent steps are the same.



 

Guess you like

Origin blog.csdn.net/bjmsb/article/details/108644477