zoukankan      html  css  js  c++  java
  • mybatis源码分析(二) 执行流程分析

    mybatis源码分析(二) 执行流程分析

     一丶环境准备

      准备只使用mybatis的环境,去掉spring等框架,方便分析

      mybatis从入门到精通(一) 入门

    二丶从SqlSession#openSession()开始分析

    //org.apache.ibatis.session.defaults.DefaultSqlSessionFactory
    public SqlSession openSession() { return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false); // 默认是不自动提交 }
      private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
        Transaction tx = null;
        try {
          final Environment environment = configuration.getEnvironment();  // 获取配置的环境, 包括事务管理, 和jdbc数据源
          final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
          tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
          
          // 获取执行器,默认是SimpleExecutor
          final Executor executor = configuration.newExecutor(tx, execType);
          
          // 返回sqlSession (sqlSession是接口层, 封装了许多客户端常用的方法)
          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();
        }
      }

    三丶获取mapper实体类

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

      Configuration

      public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        return mapperRegistry.getMapper(type, sqlSession);
      }
     MapperRegistry
      @SuppressWarnings("unchecked")
      public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        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); //mapper代理工厂, 生成对应的代理对象
        } catch (Exception e) {
          throw new BindingException("Error getting mapper instance. Cause: " + e, e);
        }
      }

    四丶MapperProxyFactory动态代理生成对应的代理类

      public T newInstance(SqlSession sqlSession) {
        //使用jdk动态代理, 需要实现jdk的接口, mapperProxy实现了对应的接口方法
        final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
        return newInstance(mapperProxy);
      }
    
      protected T newInstance(MapperProxy<T> mapperProxy) { //使用jdk生成动态代理对象
        return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
      }

    五丶调用Mapper方法,  实际调用MapperProxy代理方法

    一个MapperProxy对应一个Mapper实体类, MapperProxy会缓存Mappper实体类的所有方法调用
      public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
        this.sqlSession = sqlSession;
        this.mapperInterface = mapperInterface;
        this.methodCache = methodCache;
      }
    
      @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
          if (Object.class.equals(method.getDeclaringClass())) { // 如果方法是object类的方法
            return method.invoke(this, args);
          } else if (isDefaultMethod(method)) { //接口的default方法
            return invokeDefaultMethod(proxy, method, args);
          }
        } catch (Throwable t) {
          throw ExceptionUtil.unwrapThrowable(t);
        }
        // 最后使用mapperMethod调用执行对应的mapperedStatement, 可以说是真正执行sql语句的入口
        // 这些动态代理, 只是为方便开发者使用对应方法, 而将执行语句与对应方法绑定而设计的
        final MapperMethod mapperMethod = cachedMapperMethod(method);
        return mapperMethod.execute(sqlSession, args);
      }
    
      private MapperMethod cachedMapperMethod(Method method) {
        return methodCache.computeIfAbsent(method, k -> new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
      }

    六丶MapperMethod分发调用sqlSession执行对应的方法

      public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
        this.command = new SqlCommand(config, mapperInterface, method);
        this.method = new MethodSignature(config, mapperInterface, method);
      }
      
     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()) {
              result = executeForMap(sqlSession, args);
            } else if (method.returnsCursor()) {
              result = executeForCursor(sqlSession, args);
            } else {
              Object param = method.convertArgsToSqlCommandParam(args);  // 解析对应的方法参数名
              
              // 最后使用SqlSession执行对应的方法 
              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;
      }
      
      
      
      public Object convertArgsToSqlCommandParam(Object[] args) {
        return paramNameResolver.getNamedParams(args);
      }
    ParamNameResolver 用于解析方法中的注解参数名
     /**
       * <p>
       * A single non-special parameter is returned without a name.
       * Multiple parameters are named using the naming rule.
       * In addition to the default names, this method also adds the generic names (param1, param2,
       * ...).
       * </p>
       */
      public Object getNamedParams(Object[] args) {
        final int paramCount = names.size();
        if (args == null || paramCount == 0) {
          return null;
        } else if (!hasParamAnnotation && paramCount == 1) {
          return args[names.firstKey()];
        } else {
          // 根据@Param中的值, 以及方法参数 , 设置成map
          final Map<String, Object> param = new ParamMap<>();
          int i = 0;
          for (Map.Entry<Integer, String> entry : names.entrySet()) {
            param.put(entry.getValue(), args[entry.getKey()]);
            // add generic param names (param1, param2, ...)
            final String genericParamName = GENERIC_NAME_PREFIX + String.valueOf(i + 1);
            // ensure not to overwrite parameter named with @Param
            if (!names.containsValue(genericParamName)) {
              param.put(genericParamName, args[entry.getKey()]);
            }
            i++;
          }
          return param;
        }
      }

    七丶DefaultSqlSession#selectOne()真正开始执行  (执行入口)

      @Override
      public <T> T selectOne(String statement, Object parameter) {
        // 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;
        }
      }
    
      @Override
      public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
        try {
            // 根据方法名, 从配置中获取对应的以根据配置解析出来的sql执行封装信息 -- mappedStatement
          MappedStatement ms = configuration.getMappedStatement(statement);
          
          // 最后由执行器执行 
          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();
        }
      }

     八丶执行器执行

      本次SqlSession默认使用SimpleExecutor, SqlSession先调用执行simpleExecutor父类BaseExecutor#query()方法

     

      1) BaseExecutor

      主要是做了本地缓存, 然后查询功能(doQuery)由子类实现

    protected BaseExecutor(Configuration configuration, Transaction transaction) {
        this.transaction = transaction;
        this.deferredLoads = new ConcurrentLinkedQueue<>();
        this.localCache = new PerpetualCache("LocalCache");  // 在执行器中, 使用Propertual做本地缓存, 它其实就是一个Map
        this.localOutputParameterCache = new PerpetualCache("LocalOutputParameterCache");
        this.closed = false;
        this.configuration = configuration;
        this.wrapper = this;
      }
    
      @SuppressWarnings("unchecked")
      @Override
      public <E> List<E> 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<E> list;
        try {
          queryStack++;
          // 首先尝试从本地缓存中获取
          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();
          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 {
          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;
      }  
      
     protected Connection getConnection(Log statementLog) throws SQLException {
        Connection connection = transaction.getConnection();  // 最后是由事务管理器获取对应的连接
        if (statementLog.isDebugEnabled()) {
          return ConnectionLogger.newInstance(connection, statementLog, queryStack);
        } else {
          return connection;
        }
      }  

       2) SimpleExecutor#doQuery()   ( 子类实现doQuery() )

      主要分成两步,  1. StatementHandler处理并执行对应的statement方法,  2. ResultSetHandler处理包装转换结果

      @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();
          // 由Configuration统一实例化封装对应的stamentHandler, 主要是用于插件链的包装
          StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
          // 预编译对应的statement , transaction获取连接, 然后由statementHanlder预编译对应statement
          // 以及转换参数类型并设置对应的参数给stmt
          stmt = prepareStatement(handler, ms.getStatementLog());
          
          // 由handler执行查询
          // resultHandler处理查询的结果
          return handler.query(stmt, resultHandler);
        } finally {
          closeStatement(stmt);
        }
      }
      
      private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
        Statement stmt;
        Connection connection = getConnection(statementLog);  //调用BaseExecutor中的getConnection方法, 最后委派给事务管理器获取对应的连接
        
        stmt = handler.prepare(connection, transaction.getTimeout());
        handler.parameterize(stmt);
        return stmt;
      }

       configuration#newStatementHandler()

      生成StatementHandler()的同时, 给它装配上插件

      public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
        // routingStatementHandler的作用主要是根据mappedStatement的类型, 生成对应类型的StatementHandler
        StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
        // 然后为该statementHandler添加拦截器
        statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
        return statementHandler;
      }

       PreparedStatementHandler#query() 真正执行Sql语句

      @Override
      public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
        PreparedStatement ps = (PreparedStatement) statement;
        ps.execute(); // 调用jdbc中的statment执行方法
        
        // 然后由结果集处理器处理返回结果
        return resultSetHandler.handleResultSets(ps);
      }

      DefaultResultSetHandler#handleResultSets()处理转换返回结果

      @Override
      public List<Object> handleResultSets(Statement stmt) throws SQLException {
        ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
    
        final List<Object> multipleResults = new ArrayList<>();
    
        int resultSetCount = 0;
        ResultSetWrapper rsw = getFirstResultSet(stmt);
    
        List<ResultMap> resultMaps = mappedStatement.getResultMaps();
        int resultMapCount = resultMaps.size();
        validateResultMapsCount(rsw, resultMapCount);
        while (rsw != null && resultMapCount > resultSetCount) {
          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);
      }

    九丶执行流程总结



    人生没有彩排,每一天都是现场直播
  • 相关阅读:
    Java中String与byte[]的转换
    移动端界面设计之尺寸篇(更新)
    移动端开发必晓
    sublime 之 vitage/emmet
    Sublime Text3工具的安装、破解、VIM功能vintage插件教程
    Sublime Text 3 快捷键总结
    iPhone Safari下iframe不显示滚动条无法滚动的解决方法
    名片设计尺寸及名片设计的注意事项
    转:『引』最全前端资源汇集
    (转)详解css3弹性盒模型(Flexbox)
  • 原文地址:https://www.cnblogs.com/timfruit/p/11482879.html
Copyright © 2011-2022 走看看