spring-mybatis-3 (mapper接口的代理和mapper接口的方法執行和sql返回值的封裝)


MapperScannerConfigurer
org.mybatis.spring.mapper.MapperScannerConfigurer#postProcessBeanDefinitionRegistry

  @Override
  public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
    if (this.processPropertyPlaceHolders) {
      processPropertyPlaceHolders();
    }

    ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
    scanner.setAddToConfig(this.addToConfig);
    //指定掃描的註解
    scanner.setAnnotationClass(this.annotationClass);
    //指定掃描的接口
    scanner.setMarkerInterface(this.markerInterface);
    scanner.setSqlSessionFactory(this.sqlSessionFactory);
    scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
    scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
    scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
    scanner.setResourceLoader(this.applicationContext);
    scanner.setBeanNameGenerator(this.nameGenerator);
    //指定的註解進行註冊
    scanner.registerFilters();
    // 解析配置的mapper接口包
  scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage,  	    	
             ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
  }

org.mybatis.spring.mapper.ClassPathMapperScanner#doScan

//將包下的class變爲 beanDefinitions 
Set<BeanDefinitionHolder> beanDefinitions = 
//調用 ClassPathBeanDefinitionScanner#doScan
super.doScan(basePackages);

//查看該方法
processBeanDefinitions(beanDefinitions);

查看
org.mybatis.spring.mapper.ClassPathMapperScanner#processBeanDefinitions

//對 BeanDefinition 的屬性進行填充值
 for (BeanDefinitionHolder holder : beanDefinitions) {
        definition = (GenericBeanDefinition) holder.getBeanDefinition();
        definition.getConstructorArgumentValues()
                   .addGenericArgumentValue(definition.getBeanClassName()); // issue #59
      // 註冊了 mapperFactoryBean class,這個是 Mapper 接口代理實例的入口類       
      // mapperFactoryBean 中的 MapperFactoryBean#getObject 方法用於生成mapper的代理類       
      definition.setBeanClass(this.mapperFactoryBean.getClass());

     // 註冊了 sqlSessionFactory
	 if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {
	        definition.getPropertyValues().add("sqlSessionFactory", 
	                    new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
	        explicitFactoryUsed = true;
	      }
 }

注意
@Autowired 在注入 UserMapper 實例時,會將 MapperFactoryBean#getObject 方法返回的實例注入

 @Autowired
 private UserMapper userMapper;

上面註冊了MapperFactoryBean類,查看該類
查看父類,發現 org.mybatis.spring.support.SqlSessionDaoSupport

  // 會調用該方法,將配置的 sqlSessionFactory 對象傳入進來
  public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
    if (!this.externalSqlSession) {
      // sqlSession 是 mybatis 的頂層接口,於數據庫交換的對象,查看該類
      this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
    }
  }

org.mybatis.spring.SqlSessionTemplate#SqlSessionTemplate(org.apache.ibatis.session.SqlSessionFactory, org.apache.ibatis.session.ExecutorType, org.springframework.dao.support.PersistenceExceptionTranslator)

//對 sqlSession 產生代理(jdk代理)
 this.sqlSessionProxy = (SqlSession) newProxyInstance(
        SqlSessionFactory.class.getClassLoader(),
        new Class[] { SqlSession.class },
        new SqlSessionInterceptor());

mapper 的代理類生成

查看
org.mybatis.spring.mapper.MapperFactoryBean#getObject
對mapper的接口類產生代理類

 @Override
  public T getObject() throws Exception {
    // 進入 SqlSessionTemplate
    return getSqlSession().getMapper(this.mapperInterface);
  }

org.mybatis.spring.SqlSessionTemplate#getMapper

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

org.apache.ibatis.session.Configuration#getMapper

 public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
  }

org.apache.ibatis.binding.MapperRegistry#getMapper

// knownMappers 容器是在解析 mapper xml時初始化的
// type 就是 mapper 的接口類
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);

// MapperProxyFactory類 實例化
// sqlSession 就是 SqlSessionTemplate
return mapperProxyFactory.newInstance(sqlSession);

org.apache.ibatis.binding.MapperProxyFactory#newInstance(org.apache.ibatis.session.SqlSession)

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

// 產生jdk代理類
// mapperInterface 是 mapper的接口類
// mapperProxy 是代理通知實現類,即實現 InvocationHandler 接口
protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

可以看出在依賴注入 mapper接口時,其實注入的是MapperProxy ,即mapper的代理類,
調用 mapper 接口方法時,會調用到 org.apache.ibatis.binding.MapperProxy#invoke

查看
org.apache.ibatis.binding.MapperProxy#invoke

final MapperMethod mapperMethod = cachedMapperMethod(method);

org.apache.ibatis.binding.MapperProxy#cachedMapperMethod

    MapperMethod mapperMethod = methodCache.get(method);
    if (mapperMethod == null) {
      //查看 MapperMethod
      mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
      methodCache.put(method, mapperMethod);
    }

org.apache.ibatis.binding.MapperMethod#MapperMethod

   this.command = new SqlCommand(config, mapperInterface, method);
    this.method = new MethodSignature(config, mapperInterface, method);

SqlCommand
org.apache.ibatis.binding.MapperMethod.SqlCommand#SqlCommand

 final String methodName = method.getName();
 final Class<?> declaringClass = method.getDeclaringClass();
 //根據方法名找到 MappedStatement 對象,MappedStatement 對象是在解析 mapper xml時初始化的
 // MappedStatement 中的 sqlSource 就是 執行sql的信息
 MappedStatement ms = resolveMappedStatement(mapperInterface, methodName, 
 		declaringClass,configuration);

返回到
org.apache.ibatis.binding.MapperMethod#MapperMethod

 this.command = new SqlCommand(config, mapperInterface, method);
  // 查看該方法
  this.method = new MethodSignature(config, mapperInterface, method);

org.apache.ibatis.binding.MapperMethod.MethodSignature#MethodSignature

// 獲取 mapper 方法的返回值類型
 Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface);
 
 //判斷返回類型是否是 void
 this.returnsVoid = void.class.equals(this.returnType);
 //判斷返回類型是否是 集合
 this.returnsMany = (configuration.getObjectFactory().isCollection(this.returnType) ||  
     this.returnType.isArray());
 this.returnsCursor = Cursor.class.equals(this.returnType);
 //判斷方法參數上爲 RowBounds 類型的是第幾個,即參數的索引
 this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
 ///判斷方法參數上爲 ResultHandler類型的是第幾個,即參數的索引
 this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);

mapper接口方法的執行

返回到
org.apache.ibatis.binding.MapperProxy#invoke
mapper 接口中的方法真正執行

return mapperMethod.execute(sqlSession, args);

org.apache.ibatis.binding.MapperMethod#execute

    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:
        //當前sql爲查詢時
        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);
          //查看該方法
          result = sqlSession.selectOne(command.getName(), param);
        }
        break;
      case FLUSH:
        result = sqlSession.flushStatements();
        break;
      default:
        throw new BindingException("Unknown execution method for: " + command.getName());
    }

org.mybatis.spring.SqlSessionTemplate#selectOne(java.lang.String, java.lang.Object)

  @Override
  public <T> T selectOne(String statement, Object parameter) {
    return this.sqlSessionProxy.<T> selectOne(statement, parameter);
  }

通過上面分析,得知 sqlSession 會有一個代理類,即 SqlSessionInterceptor,所以調用sqlSession方法時會進入到代理類 SqlSessionInterceptor#invoke

查看sqlSession 代理通知類
org.apache.ibatis.session.SqlSessionManager.SqlSessionInterceptor#invoke

@Override
    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 {
        //SqlSession中方法執行的結果
        Object result = method.invoke(sqlSession, args);
        if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
          sqlSession.commit(true);
        }
        return result;
      } catch (Throwable t) {
        Throwable unwrapped = unwrapThrowable(t);
        throw unwrapped;
      } finally {
        if (sqlSession != null) {
          closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
        }
      }
    }

org.mybatis.spring.SqlSessionUtils#getSqlSession(org.apache.ibatis.session.SqlSessionFactory, org.apache.ibatis.session.ExecutorType, org.springframework.dao.support.PersistenceExceptionTranslator)

  session = sessionFactory.openSession(executorType);

org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSession(org.apache.ibatis.session.ExecutorType)

return openSessionFromDataSource(execType, null, false);

org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSessionFromDataSource

// Executor :mybatis執行器,負責Sql的生成和查詢
final Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);

org.apache.ibatis.session.Configuration#newExecutor(org.apache.ibatis.transaction.Transaction, org.apache.ibatis.session.ExecutorType)

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) {
      executor = new ReuseExecutor(this, transaction);
    } else {
    //默認使用這個
      executor = new SimpleExecutor(this, transaction);
    }
    if (cacheEnabled) {
      executor = new CachingExecutor(executor);
    }
    // mybatis 插件執行,即sql攔截器
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
  }

mybatis 插件 在 mybatis的全局配置文件中配置

返回到
org.mybatis.spring.SqlSessionTemplate.SqlSessionInterceptor#invoke

// SqlSession中方法執行的結果,SqlSession 對象是 DefaultSqlSession
Object result = method.invoke(sqlSession, args);

例如DefaultSqlSession#selectOne 方法執行
org.apache.ibatis.session.defaults.DefaultSqlSession#selectOne(java.lang.String, java.lang.Object)

 @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.<T>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 {
    // statement 是mapper xml定義的mapper的命名空間加方法的字符串
    // 每個方法都會封裝成 MappedStatement 對象
      MappedStatement ms = configuration.getMappedStatement(statement);
      //mybatis執行器操作,如果配置有mybatis的插件時,則會進入到配置的插件中
      // 查看 query 方法,見下
      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();
    }
  }

wrapCollection(parameter) 查數包裝
從這裏可以看出,在使有 foreach 標籤時,默認 collection 元素值 使用這裏定義的別名中取值

private Object wrapCollection(final Object object) {
    if (object instanceof Collection) {
      StrictMap<Object> map = new StrictMap<Object>();
      map.put("collection", object);
      if (object instanceof List) {
        map.put("list", object);
      }
      return map;
    } else if (object != null && object.getClass().isArray()) {
      StrictMap<Object> map = new StrictMap<Object>();
      map.put("array", object);
      return map;
    }
    return object;
  }

org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler)

  @Override
  public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    //查看 getBoundSql,分析:DynamicSqlSource
    BoundSql boundSql = ms.getBoundSql(parameterObject);
    CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
    return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

org.apache.ibatis.scripting.xmltags.DynamicSqlSource#getBoundSql

   DynamicContext context = new DynamicContext(configuration, parameterObject);
    //例如,調到 IfSqlNode#apply
    // 執行完下面的方法 apply,此時 DynamicContext#sqlBuilder 中會有一個完整的sql,
    // 這個sql就是動態生成後的,最終需要執行的sql語句
    // 例如sqlBuilder中的最終sql:  SELECT * from t_user WHERE id=#{id} 
    rootSqlNode.apply(context);

IfSqlNode#apply
org.apache.ibatis.scripting.xmltags.IfSqlNode#apply

  @Override
  public boolean apply(DynamicContext context) {
    // 判斷 test 中的表達式是否成立
    // test: 表達式字符串
    // context.getBindings() mapper方法的參數信息
    if (evaluator.evaluateBoolean(test, context.getBindings())) {
      //成立時,則迭代下一個,因爲動態標籤中可能有多個sqlNode
      contents.apply(context);
      return true;
    }
    return false;
  }

返回到
org.apache.ibatis.scripting.xmltags.DynamicSqlSource#getBoundSql

  @Override
  public BoundSql getBoundSql(Object parameterObject) {
    DynamicContext context = new DynamicContext(configuration, parameterObject);
    rootSqlNode.apply(context);
    //上面已將動態的sql解析成 需要執行的sql,但是還未解析 例如:#{id} 這樣的格式
    SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
    Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
    // 解析 #{} 的格式,查看 parse 方法
    SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
    BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
    for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) {
      boundSql.setAdditionalParameter(entry.getKey(), entry.getValue());
    }
    return boundSql;
  }

org.apache.ibatis.builder.SqlSourceBuilder#parse

  public SqlSource parse(String originalSql, Class<?> parameterType, Map<String, Object> additionalParameters) {
    ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType, additionalParameters);
    GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);
    // 將sql中的 #{} 變爲了 ?
    // 例如:SELECT * from t_user  WHERE id=?
    String sql = parser.parse(originalSql);
    return new StaticSqlSource(configuration, sql, handler.getParameterMappings());
  }

查看 parser.parse(originalSql) 方法,其中 handler.handleToken(expression.toString())會用調用到
org.apache.ibatis.builder.SqlSourceBuilder.ParameterMappingTokenHandler#handleToken會返回一個 ? 字符。
爲什麼將 #{} 變爲了 ?,因爲jdbc要預編譯,預編譯必須要用?做爲佔位符

org.apache.ibatis.builder.SqlSourceBuilder.ParameterMappingTokenHandler#handleToken

   @Override
    public String handleToken(String content) {
    // 查看 buildParameterMapping 方法
      parameterMappings.add(buildParameterMapping(content));
      return "?";
    }

org.apache.ibatis.builder.SqlSourceBuilder.ParameterMappingTokenHandler#buildParameterMapping


 Map<String, String> propertiesMap = parseParameterMapping(content);
  String property = propertiesMap.get("property");

      for (Map.Entry<String, String> entry : propertiesMap.entrySet()) {
        String name = entry.getKey();
        String value = entry.getValue();
       if ("javaType".equals(name)) {
          javaType = resolveClass(value);
          builder.javaType(javaType);
        } else if ("jdbcType".equals(name)) {
          builder.jdbcType(resolveJdbcType(value));
        } else if ("mode".equals(name)) {
          builder.mode(resolveParameterMode(value));
        } else if ("numericScale".equals(name)) {
          builder.numericScale(Integer.valueOf(value));
        } else if ("resultMap".equals(name)) {
          builder.resultMapId(value);
        } else if ("typeHandler".equals(name)) {
          typeHandlerAlias = value;
        } else if ("jdbcTypeName".equals(name)) {
          builder.jdbcTypeName(value);
        } else if ("property".equals(name)) {
          // Do Nothing
        } else if ("expression".equals(name)) {
          throw new BuilderException("Expression based parameters are not supported yet");
        } else {
          throw new BuilderException("An invalid property '" + name + "' was found in mapping #{" + content + "}.  Valid properties are " + parameterProperties);
        }
      }

返回到
org.apache.ibatis.scripting.xmltags.DynamicSqlSource#getBoundSql

SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, 	
		 context.getBindings());
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);

BoundSql 類中的屬性

  • sql
    被 執行的sql ,例如 SELECT * from t_user WHERE id=?
  • parameterObject
    被 執行的sql的入參信息

返回到
org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler)

  @Override
  public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    //上面已解析
    BoundSql boundSql = ms.getBoundSql(parameterObject);
    CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
    //查看該方法
    return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

 return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);

org.apache.ibatis.executor.BaseExecutor#query

list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);

org.apache.ibatis.executor.BaseExecutor#queryFromDatabase

 list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);

org.apache.ibatis.executor.SimpleExecutor#doQuery

 Configuration configuration = ms.getConfiguration();
      // newStatementHandler 這裏有mybatis的攔截器的入口 
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.<E>query(stmt, resultHandler);

org.apache.ibatis.session.Configuration#newStatementHandler

  // 查看 RoutingStatementHandler
  StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
    return statementHandler;

org.apache.ibatis.executor.statement.RoutingStatementHandler#RoutingStatementHandler

    switch (ms.getStatementType()) {
      case STATEMENT:
        delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case PREPARED:
        //預編譯類型,會走到這裏,查看 PreparedStatementHandler
        delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case CALLABLE:
        delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      default:
        throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
    }

查看 PreparedStatementHandler 的父類
org.apache.ibatis.executor.statement.BaseStatementHandler#BaseStatementHandler

// 返回代理對象,負責對用戶傳遞的參數轉換成 Jdbc statement 所需要的參數
  this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
// 返回代理對象,jdbc 返回的 ResultSet結果集轉成List類的集合  
    this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);

返回到
org.apache.ibatis.executor.SimpleExecutor#doQuery

 stmt = prepareStatement(handler, ms.getStatementLog());

org.apache.ibatis.executor.SimpleExecutor#prepareStatement

private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    //這裏獲取的是Connection 的代理對象
    Connection connection = getConnection(statementLog);
    //初始化 Statement 對象
    stmt = handler.prepare(connection, transaction.getTimeout());
    //設置預編譯參數的值,即設置佔位符的參數值
    handler.parameterize(stmt);
    return stmt;
  }

org.apache.ibatis.type.TypeHandlerRegistry類中註冊了 javaType 和 JdbcType的類型處理器,根據傳參的參數類型獲取對應的處理器

org.apache.ibatis.executor.statement.BaseStatementHandler#prepare

     //查看該方法
     statement = instantiateStatement(connection);
      setStatementTimeout(statement, transactionTimeout);
      setFetchSize(statement);
      return statement;

org.apache.ibatis.executor.statement.PreparedStatementHandler#instantiateStatement

@Override
  protected Statement instantiateStatement(Connection connection) throws SQLException {
    String sql = boundSql.getSql();
    if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
      String[] keyColumnNames = mappedStatement.getKeyColumns();
      if (keyColumnNames == null) {
        return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
      } else {
        return connection.prepareStatement(sql, keyColumnNames);
      }
    } else if (mappedStatement.getResultSetType() != null) {
      return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    } else {
       //調用這個方法時,會進入到代理對象類中,connection對象其實是個代理
      return connection.prepareStatement(sql);
    }
  }

org.apache.ibatis.logging.jdbc.ConnectionLogger#invoke

if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, params);
      }    
      if ("prepareStatement".equals(method.getName())) {
        if (isDebugEnabled()) {
          debug(" Preparing: " + removeBreakingWhitespace((String) params[0]), true);
        }        
        PreparedStatement stmt = (PreparedStatement) method.invoke(connection, params);
        // 對PreparedStatement  進行代理
        stmt = PreparedStatementLogger.newInstance(stmt, statementLog, queryStack);
        return stmt;
      } else if ("prepareCall".equals(method.getName())) {
        if (isDebugEnabled()) {
          debug(" Preparing: " + removeBreakingWhitespace((String) params[0]), true);
        }        
        PreparedStatement stmt = (PreparedStatement) method.invoke(connection, params);
        stmt = PreparedStatementLogger.newInstance(stmt, statementLog, queryStack);
        return stmt;
      } else if ("createStatement".equals(method.getName())) {
        Statement stmt = (Statement) method.invoke(connection, params);
        stmt = StatementLogger.newInstance(stmt, statementLog, queryStack);
        return stmt;
      } else {
        return method.invoke(connection, params);
      }

返回到
org.apache.ibatis.executor.SimpleExecutor#prepareStatement

   //stmt 就是一個代理對象,見上面解析
   stmt = handler.prepare(connection, transaction.getTimeout());
    //設置參數,內部方法:typeHandler.setParameter(ps, i + 1, value, jdbcType);
    handler.parameterize(stmt);

Statement 設置值時,會 stmt.setString(設置sql中?的參數的索引,參數值)

返回到
org.apache.ibatis.executor.SimpleExecutor#doQuery

stmt = prepareStatement(handler, ms.getStatementLog());
//查看該方法
return handler.<E>query(stmt, resultHandler);

org.apache.ibatis.executor.statement.PreparedStatementHandler#query

  @Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    //sql真正的執行
    ps.execute();
    // sql結果集的處理
    return resultSetHandler.<E> handleResultSets(ps);
  }

sql執行結果的返回封裝

org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleResultSets

 int resultSetCount = 0;
 //查看該方法
ResultSetWrapper rsw = getFirstResultSet(stmt);
int resultMapCount = resultMaps.size();
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
  while (rsw != null && resultMapCount > resultSetCount) {
      ResultMap resultMap = resultMaps.get(resultSetCount);
       // 對sql的結果集進行處理
      handleResultSet(rsw, resultMap, multipleResults, null);
      rsw = getNextResultSet(stmt);
      cleanUpAfterHandlingResultSet();
      resultSetCount++;
    }

getFirstResultSet

private ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException {
    //獲取sql執行的結果集
    ResultSet rs = stmt.getResultSet();
    while (rs == null) {
      // move forward to get the first resultset in case the driver
      // doesn't return the resultset as the first result (HSQLDB 2.1)
      if (stmt.getMoreResults()) {
        rs = stmt.getResultSet();
      } else {
        if (stmt.getUpdateCount() == -1) {
          // no more results. Must be no resultset
          break;
        }
      }
    }
     // 查看該方法 ResultSetWrapper
    return rs != null ? new ResultSetWrapper(rs, configuration) : null;
  }

org.apache.ibatis.executor.resultset.ResultSetWrapper#ResultSetWrapper

public ResultSetWrapper(ResultSet rs, Configuration configuration) throws SQLException {
    super();
    // 從配置中獲取 類型轉換器
    this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
    this.resultSet = rs;
    // sql執行後的元信息,
    final ResultSetMetaData metaData = rs.getMetaData();
    final int columnCount = metaData.getColumnCount();
    for (int i = 1; i <= columnCount; i++) {
      columnNames.add(configuration.isUseColumnLabel() ? metaData.getColumnLabel(i) : metaData.getColumnName(i));
      //每一列的類型
      jdbcTypes.add(JdbcType.forCode(metaData.getColumnType(i)));
      classNames.add(metaData.getColumnClassName(i));
    }
  }

handleResultSet
org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleResultSet

       if (resultHandler == null) {
          DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
           //查看該方法
          handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
          multipleResults.add(defaultResultHandler.getResultList());
        }

org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleRowValues

 handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);

org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleRowValuesForSimpleResultMap

// 跳過分頁
 skipRows(rsw.getResultSet(), rowBounds);
 // rsw.getResultSet().next() 循環每一行的記錄
  while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
        //循環每一行,封裝每一行的值到對象中
		Object rowValue = getRowValue(rsw, discriminatedResultMap);
  }

 

RowBounds 邏輯分頁,一般不用 offset 從哪一個記錄開始, limit 查詢出記錄的個數

org.apache.ibatis.executor.resultset.DefaultResultSetHandler#getRowValue(org.apache.ibatis.executor.resultset.ResultSetWrapper, org.apache.ibatis.mapping.ResultMap)

// 創建一個要返回的空對象
 Object rowValue = createResultObject(rsw, resultMap, lazyLoader, null);
 
 foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;

org.apache.ibatis.executor.resultset.DefaultResultSetHandler#applyPropertyMappings

  // 這個就是mapper xml中的 resultMap
  final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
      for (ResultMapping propertyMapping : propertyMappings) {
       //mapper xml中的 resultMap中的每一行處理,也就是每一列的處理
       Object value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix);

// 將值設置到上面創建的空對象中
 metaObject.setValue(property, value);
      }

getPropertyMappingValue
org.apache.ibatis.executor.resultset.DefaultResultSetHandler#getPropertyMappingValue

// 類型
 final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();
// 根據列名獲取值
 return typeHandler.getResult(rs, column);

org.apache.ibatis.type.BaseTypeHandler#getResult(java.sql.ResultSet, java.lang.String)

result = getNullableResult(rs, columnName);

根據相應的類型處理器處理值
在這裏插入圖片描述

返回到
org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleRowValuesForSimpleResultMap

Object rowValue = getRowValue(rsw, discriminatedResultMap);
storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());

org.apache.ibatis.executor.resultset.DefaultResultSetHandler#storeObject

callResultHandler(resultHandler, resultContext, rowValue);

org.apache.ibatis.executor.resultset.DefaultResultSetHandler#callResultHandler

  private void callResultHandler(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue) {
    resultContext.nextResultObject(rowValue);
     //查看 handleResult 方法
    ((ResultHandler<Object>) resultHandler).handleResult(resultContext);
  }

org.apache.ibatis.executor.result.DefaultResultHandler#handleResult
將封裝的結果對象添加到list中

@Override
  public void handleResult(ResultContext<? extends Object> context) {
    list.add(context.getResultObject());
  }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章