Mybatis执行SQL过程

1. 相关代码

@Test
    public void test2() throws Exception{
        // 1.获取配置文件
        InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
        // 2.加载解析配置文件并获取SqlSessionFactory对象
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        // 3.根据SqlSessionFactory对象获取SqlSession对象
        SqlSession sqlSession = factory.openSession();
        // 4.通过SqlSession中提供的 API方法来操作数据库
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.selectUserById(1);
        System.out.println(user);
        // 5.关闭会话
        sqlSession.close();
    }

2. 创建SqlSession

 SqlSession sqlSession = factory.openSession();

  @Override
  public SqlSession openSession() {
    // configuration.getDefaultExecutorType() 获取默认的 Executor的类型 SIMPLE
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
  }

获取默认执行器ExecutorType.SIMPLE。

  • 继续看openSessionFromDataSource:
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      final Environment environment = configuration.getEnvironment();
      // 获取事务工厂,之前解析全局文件的时候创建过
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      // 创建事务
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      // 根据事务工厂和默认的执行器类型,创建执行器 >>
      final Executor executor = configuration.newExecutor(tx, execType);
      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();
    }
  }
  • 根据事务工厂和默认的执行器类型,创建执行器
  /**
   * 1. 完成执行器的创建(Executor)
   * 2. 完成二级缓存的设置  装饰器模式
   * 3. 完成插件逻辑的植入  装饰器模式
   * @param transaction  事务管理器
   * @param executorType 默认是 Simple
   * @return
   */
  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) { // 针对 Statement 对象做缓存
      executor = new ReuseExecutor(this, transaction);
    } else {
      // 默认 SimpleExecutor 每一次只是SQL操作都创建一个新的Statement对象
      executor = new SimpleExecutor(this, transaction);
    }
    // 二级缓存开关,settings 中的 cacheEnabled 默认是 true
    // 映射文件中 <cache> 标签 --> 创建 Cache对象
    // settings 中的 cacheEnabled = true 真正的对 Executor 做了缓存的增强
    if (cacheEnabled) {
      // 穿衣服的事情 --> 装饰器模式
      executor = new CachingExecutor(executor);
    }
    // 植入插件的逻辑,至此,四大对象已经全部拦截完毕
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
  }

最后返回DefaultSqlSession对象。

总结:创建会话的过程,我们获得了一个DefaultSqlSession,里面包含了一个Executor,Executor是SQL的实际执行对象。

3. 创建Mapper代理对象

 // 4.通过SqlSession中提供的 API方法来操作数据库
 UserMapper mapper = sqlSession.getMapper(UserMapper.class);

继续F7,

 @Override
  public <T> T getMapper(Class<T> type) {
    return configuration.getMapper(type, this);
  }

继续F7,


  /**
   * 怎么获取 Mapper 接口的代理对象
   * 存储关系:
   *    1.系统启动的时候
   *       接口类型 --》 MapperProxyFactory --》 MapperProxy --> MapperMethod
   *       的映射关系存储在 MapperRegistry 中
   *
   *  获取Mapper代理对象
   *      根据传递的接口类型 从 MapperRegistry 中获取对应的
   *      MapperProxyFactory对象
   *      然后 根据 MapperProxyFactory 对象获取 MapperProxy对象
   * @param type
   * @param sqlSession
   * @param <T>
   * @return
   */
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    // mapperRegistry中注册的有Mapper的相关信息 在解析映射文件时 调用过addMapper方法
    return mapperRegistry.getMapper(type, sqlSession);
  }

继续F7,

 /**
   * 获取Mapper接口对应的代理对象
   */
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    // 获取Mapper接口对应的 MapperProxyFactory 对象
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
      // 通过工厂对象创建代理对象
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }

进入newInstance方法

这里创建MapperProxy对象

 public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }

实际底层是JDK动态代理。

 /**
   * 创建实现了 mapperInterface 接口的代理对象
   */
  protected T newInstance(MapperProxy<T> mapperProxy) {
    // 1:类加载器:2:被代理类实现的接口、3:实现了 InvocationHandler 的触发管理类
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

在代码中发现代理对象是通过JDK动态代理创建,返回的代理对象。而且里面也传递了一个实现了InvocationHandler接口的触发管理类。
在这里插入图片描述

总结:获得Mapper对象的过程,实质上是获取了一个JDK动态代理对象(类型是$ProxyN)。这个代理类会继承Proxy类,实现被代理的接口,里面持有了一个MapperProxy类型的触发管理类。

4.sql的执行

4.1 MapperProxy.invoke()

User user = mapper.selectUserById(1);

由于所有的Mapper都是JDK动态代理对象,所以任意的方法都是执行触发管理类MapperProxy的invoke()方法。

 @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      // toString hashCode equals getClass等方法,无需走到执行SQL的流程
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      } else {
        // 提升获取 mapperMethod 的效率,到 MapperMethodInvoker(内部接口) 的 invoke
        // 普通方法会走到 PlainMethodInvoker(内部类) 的 invoke
        return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
  }

然后进入到PlainMethodInvoker的invoke方法.

 @Override
    public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
      // SQL执行的真正起点
      return mapperMethod.execute(sqlSession, args);
    }

4.2 mapperMethod.execute()

 public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    switch (command.getType()) { // 根据SQL语句的类型调用SqlSession对应的方法
      case INSERT: {
        // 通过 ParamNameResolver 处理args[] 数组 将用户传入的实参和指定参数名称关联起来
        Object param = method.convertArgsToSqlCommandParam(args);
        // sqlSession.insert(command.getName(), param) 调用SqlSession的insert方法
        // rowCountResult 方法会根据 method 字段中记录的方法的返回值类型对结果进行转换
        result = rowCountResult(sqlSession.insert(command.getName(), param));
        break;
      }
      case UPDATE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.update(command.getName(), param));
        break;
      }
      case DELETE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.delete(command.getName(), param));
        break;
      }
      case SELECT:
        if (method.returnsVoid() && method.hasResultHandler()) {
          // 返回值为空 且 ResultSet通过 ResultHandler处理的方法
          executeWithResultHandler(sqlSession, args);
          result = null;
        } else if (method.returnsMany()) {
          result = executeForMany(sqlSession, args);
        } else if (method.returnsMap()) {
          result = executeForMap(sqlSession, args);
        } else if (method.returnsCursor()) {
          result = executeForCursor(sqlSession, args);
        } else {
          // 返回值为 单一对象的方法
          Object param = method.convertArgsToSqlCommandParam(args);
          // 普通 select 语句的执行入口 >>
          result = sqlSession.selectOne(command.getName(), param);
          if (method.returnsOptional()
              && (result == null || !method.getReturnType().equals(result.getClass()))) {
            result = Optional.ofNullable(result);
          }
        }
        break;
      case FLUSH:
        result = sqlSession.flushStatements();
        break;
      default:
        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;
  }

在这一步,根据不同的type(INSERT、UPDATE、DELETE、SELECT)和返回类型:

1)调用convertArgsToSqlCommandParam()将方法参数转换为SQL的参数。

2)调用sqlSession的insert()、update()、delete()、selectOne ()方法。我们以查询为例,会走到selectOne()方法。

4.3 sqlSession.selectOne

 @Override
  public <T> T selectOne(String statement, Object parameter) {
    // 来到了 DefaultSqlSession
    // Popular vote was to return null on 0 results and throw exception on too many.
    List<T> list = this.selectList(statement, parameter);
    if (list.size() == 1) {
      return list.get(0);
    } else if (list.size() > 1) {
      throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
    } else {
      return null;
    }
  }

在SelectList()中,我们先根据command name(Statement ID)从Configuration中拿到MappedStatement。ms里面有xml中增删改查标签配置的所有属性,包括id、statementType、sqlSource、useCache、入参、出参等等.


  /**
   *  SqlSession 是调用者完成数据库操作的 接口
   *      那么在SqlSession 内部其实是通过 Executor来完成具体的 数据库操作的
   * @param statement  com.bobo.mybati.dao.UserMapper.query
   * @param parameter
   * @param rowBounds
   * @param <E>
   * @return
   */
  @Override
  public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
      // MappedStatement 记录了一个 select 标签所具有的所有的信息
      MappedStatement ms = configuration.getMappedStatement(statement);
      // 如果 cacheEnabled = true(默认),Executor会被 CachingExecutor装饰  wrapCollection(parameter) 对参数进行处理
      return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

然后执行了Executor的query()方法。

Executor是第二步openSession的时候创建的,创建了执行器基本类型之后,依次执行了二级缓存装饰,和插件包装。

所以,如果有被插件包装,这里会先走到插件的逻辑。如果没有显式地在settings中配置cacheEnabled=false,再走到CachingExecutor的逻辑,然后会走到BaseExecutor的query()方法。

先忽略插件。

4.4 CachingExecutor.query()

  @Override
  public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    // 获取SQL
    BoundSql boundSql = ms.getBoundSql(parameterObject);
    // 创建CacheKey:什么样的SQL是同一条SQL? >>
    // select * from t_user   select id,username,password form t_user
    // 根据特定的规则生成一个key 保证不冲突
    CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
    return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

  @Override
  public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
      throws SQLException {
    Cache cache = ms.getCache();
    // cache 对象是在哪里创建的?  XMLMapperBuilder类 xmlconfigurationElement()
    // 由 <cache> 标签决定  控制二级缓存的开关有两个 一个是 CacheEnabled 全局配置文件中的settings 配置  --》 装饰执行器 Executor  CachingExecutor
    //                                         一个是 cache 标签 映射文件中的配置  创建 Cache 对象
    if (cache != null) {
      // flushCache="true" 清空一级二级缓存 >>
      flushCacheIfRequired(ms);
      // 在 select 标签中 配置了 useCache 属性
      if (ms.isUseCache() && resultHandler == null) {
        ensureNoOutParams(ms, boundSql);
        // 获取二级缓存
        // 缓存通过 TransactionalCacheManager、TransactionalCache 管理
        @SuppressWarnings("unchecked")
        List<E> list = (List<E>) tcm.getObject(cache, key);
        if (list == null) {
          // 表示二级缓存中没有数据  那么数据进一步查询处理
          list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
          // 写入二级缓存
          tcm.putObject(cache, key, list); // issue #578 and #116
        }
        return list;
      }
    }
    // 走到 SimpleExecutor | ReuseExecutor | BatchExecutor
    return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

4.5 BaseExecutor.query方法


  /**
   * queryStack 和 占位符的作用
   * 1.查询 学校    正常查询 --> 放入一级缓存
   * 2.查询  学校的学生  正常查询 --> 放入一级缓存
   * 3.查询  学生的学校  延迟加载,从缓存中获取
   */
  @SuppressWarnings("unchecked")
  @Override
  public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    // 异常体系之 ErrorContext
    ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
    if (closed) {
      throw new ExecutorException("Executor was closed.");
    }
    if (queryStack == 0 && ms.isFlushCacheRequired()) {
      // flushCache="true"时,即使是查询,也清空一级缓存
      clearLocalCache();
    }
    List<E> list;
    try {
      // 防止递归查询重复处理缓存
      queryStack++;
      // 查询一级缓存
      // ResultHandler 和 ResultSetHandler的区别  一级缓存
      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();
      // 如果LocalCacheScope的值设置为 STATEMENT 则一级缓存失效
      if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
        // issue #482
        clearLocalCache();
      }
    }
    return list;
  }

  private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    List<E> list;
    // 先占位 也就是表示 一级缓存中已经有数据了,只是操作还没有完成 ,相同的操作不用查询数据库了
    localCache.putObject(key, EXECUTION_PLACEHOLDER);
    try {
      // 三种 Executor 的区别,看doUpdate
      // 默认Simple
      list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
    } finally {
      // 移除占位符
      localCache.removeObject(key);
    }
    // 写入一级缓存
    localCache.putObject(key, list);
    if (ms.getStatementType() == StatementType.CALLABLE) {
      localOutputParameterCache.putObject(key, parameter);
    }
    return list;
  }

4.6 SimpleExecutor.doQuery方法


  /**
   * 到了 具体的数据库操作的步骤了  JDBC
   *     Connection
   *     Statement
   *     PreparedStatement
   * @param ms
   * @param parameter
   * @param rowBounds
   * @param resultHandler
   * @param boundSql
   * @param <E>
   * @return
   * @throws SQLException
   */
  @Override
  public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    Statement stmt = null;
    try {
      Configuration configuration = ms.getConfiguration();
      // 注意,已经来到SQL处理的关键对象 StatementHandler >>  同时会完成  parameterHandler和resultSetHandler的实例化
      // 默认创建的是 PreparedStatementHandler
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      // 获取一个 Statement对象  对占位符处理
      stmt = prepareStatement(handler, ms.getStatementLog());
      // 执行查询
      return handler.query(stmt, resultHandler);
    } finally {
      // 用完就关闭
      closeStatement(stmt);
    }
  }

执行查询操作,如果有插件包装,会先走到被拦截的业务逻辑。

// 执行查询
      return handler.query(stmt, resultHandler);

  @Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    // 如果放开日志 PreparedStatement 其实是一个 PreparedStatementLogger 的代理对象
    PreparedStatement ps = (PreparedStatement) statement;
    // 到了JDBC的流程
    ps.execute(); // 如果是代理对象的话 同样的会进入到 invoke 方法中
    // 处理结果集
    return resultSetHandler.handleResultSets(ps);
  }

执行PreparedStatement的execute()方法,后面就是JDBC包中的PreparedStatement的执行了。
ResultSetHandler处理结果集,如果有插件包装,会先走到被拦截的业务逻辑。

5. sql解析和执行过程中涉及类的介绍

5.1 XMLConfigBuilder

解析全局配置文件和mapper文件;

5.2 XMLMapperBuilder

具体解析mapper文件;

5.3 MapperBuilderAssistant

协助XMLMapperBuilder解析mapper的各种标签,比如缓存标签cashe,select,insert,update,delete等。

5.4 Cache

缓存标签解析完放在类Configuration的caches变量

protected final Map<String, Cache> caches = new StrictMap<>("Caches collection");

5.5 ResultMap

解析resultMap标签的结果,最终放在类Configuration的resultMaps 变量

 protected final Map<String, ResultMap> resultMaps = new StrictMap<>("Result Maps collection");

5.6 XNode

sql标签最终解析方法类Configuration的sqlFragments变量
protected final Map<String, XNode> sqlFragments = new StrictMap<>(“XML fragments parsed from previous mappers”);

5.7 XMLStatementBuilder

select,update,insert,delete等标签的解析器

5.8 MappedStatement

重重重要,select,update,insert,delete标签最终解析结果方法这个类里面。最后放在Configuration的mappedStatements变量

public final class MappedStatement {

  private String resource;
  private Configuration configuration;
  private String id;
  private Integer fetchSize;
  private Integer timeout;
  private StatementType statementType;
  private ResultSetType resultSetType;
  private SqlSource sqlSource;
  private Cache cache;
  private ParameterMap parameterMap;
  private List<ResultMap> resultMaps;
  private boolean flushCacheRequired;
  private boolean useCache;
  private boolean resultOrdered;
  private SqlCommandType sqlCommandType;
  private KeyGenerator keyGenerator;
  private String[] keyProperties;
  private String[] keyColumns;
  private boolean hasNestedResultMaps;
  private String databaseId;
  private Log statementLog;
  private LanguageDriver lang;
  private String[] resultSets;

  MappedStatement() {
    // constructor disabled
  }
}
// 保存的就是 所有的映射文件的信息 每一个映射文件 对应一个MappedStatement对象
  protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection")
      .conflictMessageProducer((savedValue, targetValue) ->
          ". please check " + savedValue.getResource() + " and " + targetValue.getResource());

5.9 SqlSource

储存sql语句。(动态sql实现的基础)

5.10 MapperProxyFactory

一个namespace命名空间创建一个MapperProxyFactory,用来创建MapperProxy。

public class MapperProxyFactory<T> {

  /**
   * MapperProxyFactory 可以创建 mapperInterface 接口的代理对象
   *     创建的代理对象要实现的接口
   */
  private final Class<T> mapperInterface;
  // 缓存
  private final Map<Method, MapperMethodInvoker> methodCache = new ConcurrentHashMap<>();

  public MapperProxyFactory(Class<T> mapperInterface) {
    this.mapperInterface = mapperInterface;
  }

  public Class<T> getMapperInterface() {
    return mapperInterface;
  }

  public Map<Method, MapperMethodInvoker> getMethodCache() {
    return methodCache;
  }

  @SuppressWarnings("unchecked")
  /**
   * 创建实现了 mapperInterface 接口的代理对象
   */
  protected T newInstance(MapperProxy<T> mapperProxy) {
    // 1:类加载器:2:被代理类实现的接口、3:实现了 InvocationHandler 的触发管理类
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

  public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }

}

5.11 MapperProxy

Mapper接口的代理对象的InvocationHandler,重要,重要。Mapper接口真正的执行逻辑这里。


  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      // toString hashCode equals getClass等方法,无需走到执行SQL的流程
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      } else {
        // 提升获取 mapperMethod 的效率,到 MapperMethodInvoker(内部接口) 的 invoke
        // 普通方法会走到 PlainMethodInvoker(内部类) 的 invoke
        return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
  }

5.12 SqlSession

接口层类,提供增、删、改、查等各种方法,创建mapper接口的代理类,管理事务。默认实现是DefaultSqlSession。拥有的属性也比较简单,有configuration和executor等。

public class DefaultSqlSession implements SqlSession {

  private final Configuration configuration;
  private final Executor executor;

  private final boolean autoCommit;
  private boolean dirty;
  private List<Cursor<?>> cursorList;

  public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
    this.configuration = configuration;
    this.executor = executor;
    this.dirty = false;
    this.autoCommit = autoCommit;
  }
}

5.13 Executor

Sql执行器。SqlSession是委托Executor 执行sql

5.14 MapperMethod

对mapper接口的反射方法的包装,由这个类统一执行 INSERT, UPDATE, DELETE, SELECT。
这个类包含两个重要的类:SqlCommand,Sql执行所需要的信息;MethodSignature方法签名。

5.14.1 SqlCommand

保存方法名和方法类型。

 public static class SqlCommand {

    private final String name; // SQL语句的的名称
    private final SqlCommandType type; // SQL 语句的类型

    public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {
      // 获取方法名称
      final String methodName = method.getName();
      final Class<?> declaringClass = method.getDeclaringClass();
      MappedStatement ms = resolveMappedStatement(mapperInterface, methodName, declaringClass,
          configuration);
      if (ms == null) {
        if (method.getAnnotation(Flush.class) != null) {
          name = null;
          type = SqlCommandType.FLUSH;
        } else {
          throw new BindingException("Invalid bound statement (not found): "
              + mapperInterface.getName() + "." + methodName);
        }
      } else {
        name = ms.getId();
        type = ms.getSqlCommandType();
        if (type == SqlCommandType.UNKNOWN) {
          throw new BindingException("Unknown execution method for: " + name);
        }
      }
    }
}
......

5.14.2 MethodSignature

 public static class MethodSignature {

    private final boolean returnsMany; // 判断返回是否为 Collection类型或者数组类型
    private final boolean returnsMap; // 返回值是否为 Map类型
    private final boolean returnsVoid; // 返回值类型是否为 void
    private final boolean returnsCursor; // 返回值类型是否为 Cursor 类型
    private final boolean returnsOptional; // 返回值类型是否为 Optional 类型
    private final Class<?> returnType; // 返回值类型
    private final String mapKey; // 如果返回值类型为 Map  则 mapKey 记录了作为 key的 列名
    private final Integer resultHandlerIndex; // 用来标记该方法参数列表中 ResultHandler 类型参数的位置
    private final Integer rowBoundsIndex; // 用来标记该方法参数列表中 rowBounds 类型参数的位置
    private final ParamNameResolver paramNameResolver; // 该方法对应的 ParamNameResolver 对象

    /**
     * 方法签名
     * @param configuration
     * @param mapperInterface
     * @param method
     */
    public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) {
      // 获取接口方法的返回类型
      Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface);
      if (resolvedReturnType instanceof Class<?>) {
        this.returnType = (Class<?>) resolvedReturnType;
      } else if (resolvedReturnType instanceof ParameterizedType) {
        this.returnType = (Class<?>) ((ParameterizedType) resolvedReturnType).getRawType();
      } else {
        this.returnType = method.getReturnType();
      }
      this.returnsVoid = void.class.equals(this.returnType);
      this.returnsMany = configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray();
      this.returnsCursor = Cursor.class.equals(this.returnType);
      this.returnsOptional = Optional.class.equals(this.returnType);
      this.mapKey = getMapKey(method);
      this.returnsMap = this.mapKey != null;
      // getUniqueParamIndex 查找指定类型的参数在 参数列表中的位置
      this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
      this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);
      this.paramNameResolver = new ParamNameResolver(configuration, method);
    }
    ....
}

5.15 MapperMethodInvoker

MapperMethod方法封装的调用器,实现有PlainMethodInvoker, DefaultMethodInvoker. 。

private static class PlainMethodInvoker implements MapperMethodInvoker {
    private final MapperMethod mapperMethod;

    public PlainMethodInvoker(MapperMethod mapperMethod) {
      super();
      this.mapperMethod = mapperMethod;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
      // SQL执行的真正起点
      return mapperMethod.execute(sqlSession, args);
    }
  }
}

5.16 BoundSql

由SqlSource和传参生成,真正的sql。
在这里插入图片描述

5.17 StatementHandler

其中之一的实现PreparedStatementHandler。初始化这个对象同时会初始化ParameterHandler,ResultSetHandler。

5.18 ParameterHandler

5.19 ResultSetHandler

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值