MyBatis的SQL执行原理

MyBatis的SQL执行原理,第1张

MyBatis的SQL执行原理

以下SQL的执行为例,描述mybatis的SQL执行过程

 public DataResponse findMemberPageListExt(Member member, PageVo pageVo) {
        DataResponse response = new DataResponse<>();
        logger.info("MemberServiceImpl.findMemberPageListExt input info:" + member);
        // 使用pagehelper插件进行分页
        PageHelper.startPage(pageVo.getCurrentPage(), pageVo.getPageSize()); 
        List list;
        try {
            // 查询数据
            list = memberDao.findMemberList(member);
            // 分页
            PageInfo memberPageInfo = new PageInfo<>(list);
            response.setData(memberPageInfo);
        } catch (ApplicationException e) {
            logger.error("query error,", e);
        }
        return response;
    }
 

mybatis SQL首先通过JDK动态代理调用MapperProxy的invoke方法

public class MapperProxy implements InvocationHandler, Serializable {  
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      if (Object.class.equals(method.getDeclaringClass())) { // Objec代理的方法执行
        return method.invoke(this, args);
      } else {
          // 执行方法调用,一般都从这里开始调用
        return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
  }

   @Override
   public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
      return mapperMethod.execute(sqlSession, args);
   }
}

mapperMethod.execute调用MapperMethod#execute,该方法根据不同的command.getType(),执行不同的SQL

public class MapperMethod {
    public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    switch (command.getType()) {
      case INSERT: { // 插入
        Object param = method.convertArgsToSqlCommandParam(args);
        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()) { // 查询结果返回空并且有返回结果需要处理的情况
          executeWithResultHandler(sqlSession, args);
          result = null;
        } else if (method.returnsMany()) { // 查询结果返回多条
          result = executeForMany(sqlSession, args);
        } else if (method.returnsMap()) { // 查询结果返回Map
          result = executeForMap(sqlSession, args);
        } else if (method.returnsCursor()) { // 查询结果返回游标
          result = executeForCursor(sqlSession, args);
        } else { // 查询结果返回单条记录
          Object param = method.convertArgsToSqlCommandParam(args);
          result = sqlSession.selectOne(command.getName(), param);
          if (method.returnsOptional()
              && (result == null || !method.getReturnType().equals(result.getClass()))) {
            result = Optional.ofNullable(result);
          }
        }
        break;
      case FLUSH: // 刷新Statements
        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;
  }
}

executeForMany(sqlSession, args)方法首先将参数转化为SQL命令参数,然后使用sqlSession执行selectList

 private  Object executeForMany(SqlSession sqlSession, Object[] args) {
    List result;
     //将参数转化为SQL命令参数
    Object param = method.convertArgsToSqlCommandParam(args);
    if (method.hasRowBounds()) {
      RowBounds rowBounds = method.extractRowBounds(args);
      result = sqlSession.selectList(command.getName(), param, rowBounds);
    } else {
         // 执行selectList
      result = sqlSession.selectList(command.getName(), param);
    }
    // issue #510 Collections & arrays support
    if (!method.getReturnType().isAssignableFrom(result.getClass())) {
      if (method.getReturnType().isArray()) {
        return convertToArray(result);
      } else {
        return convertToDeclaredCollection(sqlSession.getConfiguration(), result);
      }
    }
    return result;
  }

sqlSession.selectList(command.getName(), param)方法会调用SqlSessionTemplate#selectList, 该方法调用代理

public class SqlSessionTemplate implements SqlSession, DisposableBean {
    
    public  List selectList(String statement, Object parameter) {
        // 调用到invoke方法
      return this.sqlSessionProxy.selectList(statement, parameter);
    }
    
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 获取SqlSession
      SqlSession sqlSession = getSqlSession(SqlSessionTemplate.this.sqlSessionFactory,
          SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);
      try {
          // 调用方法
        Object result = method.invoke(sqlSession, args);
        if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) { // 带事务时强制提交/回滚
          // force commit even on non-dirty sessions because some databases require
          // a commit/rollback before calling close()
          sqlSession.commit(true);
        }
        return result;
      } catch (Throwable t) {
        Throwable unwrapped = unwrapThrowable(t);
        if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
          // release the connection to avoid a deadlock if the translator is no loaded. See issue #22
          closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
          sqlSession = null;
          Throwable translated = SqlSessionTemplate.this.exceptionTranslator
              .translateExceptionIfPossible((PersistenceException) unwrapped);
          if (translated != null) {
            unwrapped = translated;
          }
        }
        throw unwrapped;
      } finally {
        if (sqlSession != null) {
          closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
        }
      }
    }
  }
}

method.invoke(sqlSession, args)会调用到DefaultSqlSession#selectList,selectList获取映射的Statements, 然后使用executor去执行查询

public class DefaultSqlSession implements SqlSession {
    @Override
    public  List selectList(String statement, Object parameter, RowBounds rowBounds) {
      try {
          // 获取映射的Statements
        MappedStatement ms = configuration.getMappedStatement(statement);
          // 使用executor去执行查询
        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();
      }
    }
}

获取映射的Statements调用了Configuration#getMappedStatement,该方法会从statements Map中根据id获取对应的statement,statements Map中的值在应用启动时,mybatis会加载

public class Configuration {
    public MappedStatement getMappedStatement(String id) {
   		 return this.getMappedStatement(id, true);
    }

    public MappedStatement getMappedStatement(String id, boolean validateIncompleteStatements) {
        if (validateIncompleteStatements) {
          buildAllStatements();
        }
        return mappedStatements.get(id);
    }
}

executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER)方法执行前会调用插件代理Plugin#invoke, 如常用的分页插件等

public class Plugin implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      try {
          // 获取方法集合
        Set methods = signatureMap.get(method.getDeclaringClass());
        if (methods != null && methods.contains(method)) {
            // 执行拦截器
          return interceptor.intercept(new Invocation(target, method, args));
        }
        return method.invoke(target, args);
      } catch (Exception e) {
        throw ExceptionUtil.unwrapThrowable(e);
      }
    }
}

这里使用了PageHelper,他会拦截查询语句,先查出总的数据数,然后在查具体数据

public class PageInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        try {
            Object[] args = invocation.getArgs();
            MappedStatement ms = (MappedStatement) args[0];
            Object parameter = args[1];
            RowBounds rowBounds = (RowBounds) args[2];
            ResultHandler resultHandler = (ResultHandler) args[3];
            Executor executor = (Executor) invocation.getTarget();
            CacheKey cacheKey;
            BoundSql boundSql;
            //由于逻辑关系,只会进入一次
            if (args.length == 4) {
                //4 个参数时
                boundSql = ms.getBoundSql(parameter);
                // 创建缓存的key
                cacheKey = executor.createCacheKey(ms, parameter, rowBounds, boundSql);
            } else {
                //6 个参数时
                cacheKey = (CacheKey) args[4];
                boundSql = (BoundSql) args[5];
            }
            // 检查对话是否存在
            checkDialectExists();
            //对 boundSql 的拦截处理
            if (dialect instanceof BoundSqlInterceptor.Chain) {
                // 绑定sql
             boundSql = ((BoundSqlInterceptor.Chain) dialect).doBoundSql(BoundSqlInterceptor.Type.ORIGINAL, boundSql, cacheKey);
            }
            List resultList;
            //调用方法判断是否需要进行分页,如果不需要,直接返回结果
            if (!dialect.skip(ms, parameter, rowBounds)) {
                //判断是否需要进行 count 查询
                if (dialect.beforeCount(ms, parameter, rowBounds)) {
                    //动态拼接SQL,查询数据总数
                    Long count = count(executor, ms, parameter, rowBounds, null, boundSql);
                    // 处理查询总数,返回 true 时继续分页查询,false 时直接返回
                    if (!dialect.afterCount(count, parameter, rowBounds)) {
                        //当查询总数为 0 时,直接返回空的结果
                        return dialect.afterPage(new ArrayList(), parameter, rowBounds);
                    }
                }
                // 查询数据列表
                resultList = ExecutorUtil.pageQuery(dialect, executor, ms, parameter, rowBounds, resultHandler, boundSql, cacheKey);
            } else {
                //rowBounds用参数值,不使用分页插件处理时,仍然支持默认的内存分页
                resultList = executor.query(ms, parameter, rowBounds, resultHandler, cacheKey, boundSql);
            }
            return dialect.afterPage(resultList, parameter, rowBounds);
        } finally {
            if(dialect != null){
                dialect.afterAll();
            }
        }
    }
}

分页查询数据调用ExecutorUtil#pageQuery

public abstract class ExecutorUtil {
    public static  List pageQuery(Dialect dialect, Executor executor, MappedStatement ms, Object parameter,
                                        RowBounds rowBounds, ResultHandler resultHandler,
                                        BoundSql boundSql, CacheKey cacheKey) throws SQLException {
        //判断是否需要进行分页查询
        if (dialect.beforePage(ms, parameter, rowBounds)) {
            //生成分页的缓存 key
            CacheKey pageKey = cacheKey;
            //处理参数对象
            parameter = dialect.processParameterObject(ms, parameter, boundSql, pageKey);
            //调用方言获取分页 sql
            String pageSql = dialect.getPageSql(ms, boundSql, parameter, rowBounds, pageKey);
            BoundSql pageBoundSql = new BoundSql(ms.getConfiguration(), pageSql, boundSql.getParameterMappings(), parameter);

            Map additionalParameters = getAdditionalParameter(boundSql);
            //设置动态参数
            for (String key : additionalParameters.keySet()) {
                pageBoundSql.setAdditionalParameter(key, additionalParameters.get(key));
            }
            //对 boundSql 的拦截处理
            if (dialect instanceof BoundSqlInterceptor.Chain) {
                pageBoundSql = ((BoundSqlInterceptor.Chain) dialect).doBoundSql(BoundSqlInterceptor.Type.PAGE_SQL, pageBoundSql, pageKey);
            }
            //执行分页查询
            return executor.query(ms, parameter, RowBounds.DEFAULT, resultHandler, pageKey, pageBoundSql);
        } else {
            //不执行分页的情况下,也不执行内存分页
            return executor.query(ms, parameter, RowBounds.DEFAULT, resultHandler, cacheKey, boundSql);
        }
}

executor.query(ms, parameter, RowBounds.DEFAULT, resultHandler, pageKey, pageBoundSql)会调用CachingExecutor#query方法

public class CachingExecutor implements Executor {
    public  List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
        throws SQLException {
      Cache cache = ms.getCache();
      if (cache != null) { // 缓存存在,从缓存里面取
        flushCacheIfRequired(ms);
        if (ms.isUseCache() && resultHandler == null) {
          ensureNoOutParams(ms, boundSql);
          @SuppressWarnings("unchecked")
          List list = (List) 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; // 缓存存在,直接返回
        }
      }
        // 执行查询
      return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
    }
}

delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql)会调用Executor#query方法,优先取缓存的值,如果缓存没有,再查询数据库

public abstract class baseExecutor implements Executor {
    @Override
    public  List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
      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()) {
        clearLocalCache();
      }
      List list;
      try {
        queryStack++;
          // 获取缓存值
        list = resultHandler == null ? (List) 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();
        if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
          // issue #482
          clearLocalCache();
        }
      }
      return list;
    }
    
    // 从数据库查询数据
    private  List queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
        List list;
        // 设置本次查询缓存占位符
        localCache.putObject(key, EXECUTION_PLACEHOLDER);
        try {
            // 查询数据
          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;
   }
}

doQuery(ms, parameter, rowBounds, resultHandler, boundSql)会根据配置调用实现了baseExecutor的子类,子类有:BatchExecutor、ClosedExecutor、ResueExecutor和SimpleExecutor

一般使用的是SimpleExecutor, 他的doQuery方法如下

public class SimpleExecutor extends baseExecutor {
    public  List doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
      Statement stmt = null;
      try {
          // 获取配置
        Configuration configuration = ms.getConfiguration();
          // 生成StatementHandler
        StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
          // 预处理Statement
        stmt = prepareStatement(handler, ms.getStatementLog());
          // 执行查询
        return handler.query(stmt, resultHandler);
      } finally {
        closeStatement(stmt);
      }
    }
}

handler.query(stmt, resultHandler)首先调用RoutingStatementHandler#query,这里会代理到PreparedStatementHandler#query

public class RoutingStatementHandler implements StatementHandler {
      @Override
      public  List query(Statement statement, ResultHandler resultHandler) throws SQLException {
        return delegate.query(statement, resultHandler);
      }
}
public class PreparedStatementHandler extends baseStatementHandler {
      @Override
      public  List query(Statement statement, ResultHandler resultHandler) throws SQLException {
          // 转化为PreparedStatement
        PreparedStatement ps = (PreparedStatement) statement;
          // 执行sql
        ps.execute();
          // 处理结果集
        return resultSetHandler.handleResultSets(ps);
      }
}

ps.execute()会调用到DruidPooledPreparedStatement#execute

public class DruidPooledPreparedStatement extends DruidPooledStatement implements PreparedStatement {
    @Override
    public boolean execute() throws SQLException {
        // 开启检查
        checkOpen();
 		// 增加执行计数器
        incrementExecuteCount();
        // 事务记录
        transactionRecord(sql);
        // 执行之前处理
        conn.beforeExecute();
        try {
            // 执行SQL
            return stmt.execute();
        } catch (Throwable t) {
            errorCheck(t);
            throw checkException(t);
        } finally {
            // 执行之后处理
            conn.afterExecute();
        }
    }
}

resultSetHandler.handleResultSets处理执行的结果时会调用结果集处理器DefaultResultSetHandler#handleResultSets

public class DefaultResultSetHandler implements ResultSetHandler {
    @Override
    public List handleResultSets(Statement stmt) throws SQLException {
      ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
      final List multipleResults = new ArrayList<>();
      int resultSetCount = 0;
        // 获取第一个结果集
      ResultSetWrapper rsw = getFirstResultSet(stmt);
        // 获取结果map
      List resultMaps = mappedStatement.getResultMaps();
        // 结果map大小
      int resultMapCount = resultMaps.size();
        // 校验总数
      validateResultMapsCount(rsw, resultMapCount);
      while (rsw != null && resultMapCount > resultSetCount) {
          // 结果map
        ResultMap resultMap = resultMaps.get(resultSetCount);
          // 处理结果集
        handleResultSet(rsw, resultMap, multipleResults, null);
          // 获取下一个结果集
        rsw = getNextResultSet(stmt);
          // 清理
        cleanUpAfterHandlingResultSet();
        resultSetCount++;
      }

      String[] resultSets = mappedStatement.getResultSets();
      if (resultSets != null) {
        while (rsw != null && resultSetCount < resultSets.length) {
          ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
          if (parentMapping != null) {
            String nestedResultMapId = parentMapping.getNestedResultMapId();
            ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
            handleResultSet(rsw, resultMap, null, parentMapping);
          }
          rsw = getNextResultSet(stmt);
          cleanUpAfterHandlingResultSet();
          resultSetCount++;
        }
      }

      return collapseSingleResultList(multipleResults);
    }
    
     public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
        if (resultMap.hasNestedResultMaps()) { // 嵌套结果集
          ensureNoRowBounds();
          checkResultHandler();
          handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
        } else { // 简单结果集
          handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
        }
    }
    
    private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler resultHandler, RowBounds rowBounds, ResultMapping parentMapping)throws SQLException {
        DefaultResultContext resultContext = new DefaultResultContext<>();
        ResultSet resultSet = rsw.getResultSet();
        skipRows(resultSet, rowBounds);
        while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
            // 区分结果map
          ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
            // 获取行值
          Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
            // 存储
          storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
        }
    }
}
					
										


					

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5682628.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)