Myabtis的SQL的执行是通过SqlSession。默认的实现类是DefalutSqlSession。通过源码可以发现,selectOne最终会调用selectList这个方法。

  1. @Override
  2. public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
  3. try {
         //获取MappedStatement 通过id 到configuration里面
  4. MappedStatement ms = configuration.getMappedStatement(statement);
  5. return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
  6. } catch (Exception e) {
  7. throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
  8. } finally {
  9. ErrorContext.instance().reset();
  10. }
  11. }

通过上面可以发现是通过Executor去执行查询。但是executor是个接口,是什么时候指定的用什么执行器呢。

因为SqlSession是通过SqlSessionFactory接口获取的,实现类是DefaultSqlSessionFactory

  1. private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
  2. Transaction tx = null;
  3. try {
  4. final Environment environment = configuration.getEnvironment();
  5. final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
  6. tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
  7. final Executor executor = configuration.newExecutor(tx, execType);
  8. return new DefaultSqlSession(configuration, executor, autoCommit);
  9. } catch (Exception e) {
  10. closeTransaction(tx); // may have fetched a connection so lets call close()
  11. throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
  12. } finally {
  13. ErrorContext.instance().reset();
  14. }
  15. }
  1. public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
  2. executorType = executorType == null ? defaultExecutorType : executorType;
  3. executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
  4. Executor executor;
  5. if (ExecutorType.BATCH == executorType) {
  6. executor = new BatchExecutor(this, transaction);
  7. } else if (ExecutorType.REUSE == executorType) {
  8. executor = new ReuseExecutor(this, transaction);
  9. } else {
  10. executor = new SimpleExecutor(this, transaction);
  11. }
  12. if (cacheEnabled) {
  13. executor = new CachingExecutor(executor);
  14. }
  15. executor = (Executor) interceptorChain.pluginAll(executor);
  16. return executor;
  17. }

可以看到默认的是SimpleExecutor;然后默认的是开启缓存的,所以最终应该是一个CachingExecutor,但是CachingExecutor有一个构造器参数是前面的执行器。

这是一种典型的装饰器设计模式

下面那行代码你现在只需要知道如果有Executor的拦截器,就会返回一个代理对象,在执行executor方法前,会执行拦截器。这是动态代理。

后面讲Myabtis拦截器原理的时候会详细介绍。

这下知道了是CachingExecotor,来看下CachingExecutor方法;

  1. public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
  2. BoundSql boundSql = ms.getBoundSql(parameterObject);
  3. CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
  4. return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  5. }

① 先看是如何获取BoundSql  这个对象,包含了sql,params等信息。

  1. public BoundSql getBoundSql(Object parameterObject) {
  2. BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
  3. List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
  4. if (parameterMappings == null || parameterMappings.isEmpty()) {
  5. boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);
  6. }
  7.  
  8. // check for nested result maps in parameter mappings (issue #30)
  9. for (ParameterMapping pm : boundSql.getParameterMappings()) {
  10. String rmId = pm.getResultMapId();
  11. if (rmId != null) {
  12. ResultMap rm = configuration.getResultMap(rmId);
  13. if (rm != null) {
  14. hasNestedResultMaps |= rm.hasNestedResultMaps();
  15. }
  16. }
  17. }

可以发现从sqlSource中获取BoundSql

一,DynamicSqlSourcre

  1. public class DynamicSqlSource implements SqlSource {
  2.  
  3. private Configuration configuration;
  4. private SqlNode rootSqlNode;
  5.  
  6. public DynamicSqlSource(Configuration configuration, SqlNode rootSqlNode) {
  7. this.configuration = configuration;
  8. this.rootSqlNode = rootSqlNode;
  9. }
  10.  
  11. @Override
  12. public BoundSql getBoundSql(Object parameterObject) {
    这一块的操作就是替换sql里面${}部分
  13. DynamicContext context = new DynamicContext(configuration, parameterObject);
  14. 14 rootSqlNode.apply(context);
  15. SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
  16. Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
  17. SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
  18. BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
  19. for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) {
  20. boundSql.setAdditionalParameter(entry.getKey(), entry.getValue());
  21. }
  22. return boundSql;
  23. }
  24.  
  25. }

来看下是如何替换sql的:

  1. public DynamicContext(Configuration configuration, Object parameterObject) {
  2. if (parameterObject != null && !(parameterObject instanceof Map)) {
    //如果参数类型不是map则构造一个MetaObject; //todo 这一块干嘛的目前还不清楚,后面研究mybatis反射时候研究
    //这个对象 保存着Configuration的那个几个factory 反射factory 驼峰Factory,创建对象factory
  3. MetaObject metaObject = configuration.newMetaObject(parameterObject);
  4. bindings = new ContextMap(metaObject);
  5. } else {
  6. bindings = new ContextMap(null);
  7. }
  8. bindings.put(PARAMETER_OBJECT_KEY, parameterObject);//_paramter
  9. bindings.put(DATABASE_ID_KEY, configuration.getDatabaseId());
  10. }

rootSqlNode.apply实际上接口的方法,这是根据节点的类别去执行,我们正常的MixedSqlNode实际上就是SqlNode数组类型,

这里只拿TextSqlNode做例子来看:

  1. @Override
  2. public boolean apply(DynamicContext context) {
  3. GenericTokenParser parser = createParser(new BindingTokenParser(context, injectionFilter));
  4. context.appendSql(parser.parse(text));
  5. return true;
  6. }

看过上一篇的应该对这段有了解, 就是用具体解析类来解析节点内容来,parser获取${}中间变量的名字,然后BindingTokenParser去处理;

parser.parses就是把sql里面每个${}替换成相应的值的作用

  1. public BindingTokenParser(DynamicContext context, Pattern injectionFilter) {
  2. this.context = context;
  3. this.injectionFilter = injectionFilter;
  4. }
  5.  
  6. @Override
  7. public String handleToken(String content) {
    //从参数对象里面获取值返回
  8. Object parameter = context.getBindings().get("_parameter");
  9. if (parameter == null) {
  10. context.getBindings().put("value", null);
    //是不是基本类型
  11. } else if (SimpleTypeRegistry.isSimpleType(parameter.getClass())) {
  12. context.getBindings().put("value", parameter);
  13. }
    //获取到对应值,这一块很复杂,有时间在研究。
  14. Object value = OgnlCache.getValue(content, context.getBindings());
  15. String srtValue = (value == null ? "" : String.valueOf(value)); // issue #274 return "" instead of "null"
  16. checkInjection(srtValue);
  17. return srtValue;
  18. }
  19.  
  20. private void checkInjection(String value) {
  21. if (injectionFilter != null && !injectionFilter.matcher(value).matches()) {
  22. throw new ScriptingException("Invalid input. Please conform to regex" + injectionFilter.pattern());
  23. }
  24. }
  25. }

好了 到此为止 sql里面${}都已经替换成该有的值了,根据变量名获取Value这一块下回研究下在另外写篇文章。

然后看这段代码:

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

这一段也很重要 实际上是填充boundSql里面parameterMapping的

来看SqlSourceBuilder

  1. public SqlSource parse(String originalSql, Class<?> parameterType, Map<String, Object> additionalParameters) {
  2. ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType, additionalParameters);
  3. GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);
  4. String sql = parser.parse(originalSql);
  5. return new StaticSqlSource(configuration, sql, handler.getParameterMappings());
  6. }

这一块代码应该很熟悉了吧, 实际上就是把#{}替换成? 同时记录下参数的类型等信息,因为逻辑前面有介绍,直接看ParameterMappingTokenHandler的方法

  1. public String handleToken(String content) {
    //记录参数
  2. parameterMappings.add(buildParameterMapping(content));
    //替换成?
  3. return "?";
  4. }
  5.  
  6. private ParameterMapping buildParameterMapping(String content) {
  7. Map<String, String> propertiesMap = parseParameterMapping(content);
  8. String property = propertiesMap.get("property");
  9. Class<?> propertyType;
  10. if (metaParameters.hasGetter(property)) { // issue #448 get type from additional params
  11. propertyType = metaParameters.getGetterType(property);
  12. } else if (typeHandlerRegistry.hasTypeHandler(parameterType)) {
  13. propertyType = parameterType;
  14. } else if (JdbcType.CURSOR.name().equals(propertiesMap.get("jdbcType"))) {
  15. propertyType = java.sql.ResultSet.class;
  16. } else if (property != null) {
  17. MetaClass metaClass = MetaClass.forClass(parameterType, configuration.getReflectorFactory());
  18. if (metaClass.hasGetter(property)) {
  19. propertyType = metaClass.getGetterType(property);
  20. } else {
  21. propertyType = Object.class;
  22. }
  23. } else {
  24. propertyType = Object.class;
  25. }
  26. ParameterMapping.Builder builder = new ParameterMapping.Builder(configuration, property, propertyType);
  27. Class<?> javaType = propertyType;
    设置每个参数类型等。
  28. String typeHandlerAlias = null;
  29. for (Map.Entry<String, String> entry : propertiesMap.entrySet()) {
  30. String name = entry.getKey();
  31. String value = entry.getValue();
  32. if ("javaType".equals(name)) {
  33. javaType = resolveClass(value);
  34. builder.javaType(javaType);
  35. } else if ("jdbcType".equals(name)) {
  36. builder.jdbcType(resolveJdbcType(value));
  37. } else if ("mode".equals(name)) {
  38. builder.mode(resolveParameterMode(value));
  39. } else if ("numericScale".equals(name)) {
  40. builder.numericScale(Integer.valueOf(value));
  41. } else if ("resultMap".equals(name)) {
  42. builder.resultMapId(value);
  43. } else if ("typeHandler".equals(name)) {
  44. typeHandlerAlias = value;
  45. } else if ("jdbcTypeName".equals(name)) {
  46. builder.jdbcTypeName(value);
  47. } else if ("property".equals(name)) {
  48. // Do Nothing
  49. } else if ("expression".equals(name)) {
  50. throw new BuilderException("Expression based parameters are not supported yet");
  51. } else {
  52. throw new BuilderException("An invalid property '" + name + "' was found in mapping #{" + content + "}. Valid properties are " + parameterProperties);
  53. }
  54. }
  55. if (typeHandlerAlias != null) {
  56. builder.typeHandler(resolveTypeHandler(javaType, typeHandlerAlias));
  57. }
  58. return builder.build();
  59. }

现在回过头开始看CachingExecutor的query方法了

  1. public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
  2. throws SQLException {
    //这块就是mybatis的二级缓存
  3. Cache cache = ms.getCache();
  4. if (cache != null) {
  5. flushCacheIfRequired(ms);
  6. if (ms.isUseCache() && resultHandler == null) {
  7. ensureNoOutParams(ms, parameterObject, boundSql);
  8. @SuppressWarnings("unchecked")
  9. List<E> list = (List<E>) tcm.getObject(cache, key);
  10. if (list == null) {
  11. list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  12. tcm.putObject(cache, key, list); // issue #578 and #116
  13. }
  14. return list;
  15. }
  16. }
    //最终调用的还是CachingExecutor里装饰的那个执行器
  17. return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  18. }

这个方法是所有执行器父类的BaseExecutor来实现的

  1. public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
  2. ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
  3. if (closed) {
  4. throw new ExecutorException("Executor was closed.");
  5. }
  6. if (queryStack == 0 && ms.isFlushCacheRequired()) {
  7. clearLocalCache();
  8. }
  9. List<E> list;
  10. try {
  11. queryStack++;
  12. list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
  13. if (list != null) {
  14. handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
  15. } else {
  16. list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
  17. }
  18. } finally {
  19. queryStack--;
  20. }
  21. if (queryStack == 0) {
  22. for (DeferredLoad deferredLoad : deferredLoads) {
  23. deferredLoad.load();
  24. }
  25. // issue #601
  26. deferredLoads.clear();
  27. if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
  28. // issue #482
  29. clearLocalCache();
  30. }
  31. }
  32. return list;
  33. }

//这里应该就是mybatis的一级缓存,直接看从数据库查询数据

  1. private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
  2. List<E> list;
  3. localCache.putObject(key, EXECUTION_PLACEHOLDER);
  4. try {
         //在子类中实现的 doQuery 查询出来结果放入一级缓存
  5. list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
  6. } finally {
  7. localCache.removeObject(key);
  8. }
  9. localCache.putObject(key, list);
  10. if (ms.getStatementType() == StatementType.CALLABLE) {
  11. localOutputParameterCache.putObject(key, parameter);
  12. }
  13. return list;
  14. }

看SimpleExecutor的doQuery的实现

  1. public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
  2. Statement stmt = null;
  3. try {
  4. Configuration configuration = ms.getConfiguration();
    //创建StatementHandler的代理对象,有的话返回代理对象,没有返回默认的RoutingStatmenthandler 典型的责任链模式
  5. StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
  6. stmt = prepareStatement(handler, ms.getStatementLog());
  7. return handler.<E>query(stmt, resultHandler);
  8. } finally {
  9. closeStatement(stmt);
  10. }
  11. }

接下来看下是怎么创建合适的Statement对象的,

  1. private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
  2. Statement stmt;
  3. Connection connection = getConnection(statementLog);
  4. stmt = handler.prepare(connection);
  5. 5 handler.parameterize(stmt);//设置参数
  6. return stmt;
  7. }

RoutingStatmenthandler

  1. @Override
  2. public Statement prepare(Connection connection) throws SQLException {
  3. return delegate.prepare(connection);
  4. }
  5.  
  6. @Override
  7. public void parameterize(Statement statement) throws SQLException {
  8. delegate.parameterize(statement);
  9. }

调用的都是装饰的statementHander ,delegate是在RoutingStatementHandler构造器初始化的;

  1. public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
  2.  
  3. switch (ms.getStatementType()) {
  4. case STATEMENT:
  5. delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
  6. break;
  7. case PREPARED:
  8. delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
  9. break;
  10. case CALLABLE:
  11. delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
  12. break;
  13. default:
  14. throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
  15. }
  16.  
  17. }

可以看出来是根据ms保存的,三张就是Statement的三种,我们直接看预编译的,PreparedStatementHandler

实际上一些公共方法在BaseStatementHandler实现了

  1. public Statement prepare(Connection connection) throws SQLException {
  2. ErrorContext.instance().sql(boundSql.getSql());
  3. Statement statement = null;
  4. try {
  5. statement = instantiateStatement(connection);
  6. setStatementTimeout(statement);
  7. setFetchSize(statement);
  8. return statement;
  9. } catch (SQLException e) {
  10. closeStatement(statement);
  11. throw e;
  12. } catch (Exception e) {
  13. closeStatement(statement);
  14. throw new ExecutorException("Error preparing statement. Cause: " + e, e);
  15. }
  16. }

instantiateStatement子类PreparedStatementHandler实现

  1. protected Statement instantiateStatement(Connection connection) throws SQLException {
  2. String sql = boundSql.getSql();
  3. if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
  4. String[] keyColumnNames = mappedStatement.getKeyColumns();
  5. if (keyColumnNames == null) {
  6. return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
  7. } else {
  8. return connection.prepareStatement(sql, keyColumnNames);
  9. }
  10. } else if (mappedStatement.getResultSetType() != null) {
  11. return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
  12. } else {
  13. return connection.prepareStatement(sql);
  14. }
  15. }

上面就是根据mappedStatement的resultType不同创建不同构造器的Statement;

下面来看下参数是怎么设置的。PreparedStatementHandler,但是handler是里面的paramterHandler是什么实现类呢?什么时候注入的呢?

  1. public void parameterize(Statement statement) throws SQLException {
  2. parameterHandler.setParameters((PreparedStatement) statement);
  3. }

来看下BaseStatementHandler的构造器

  1. protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
  2. this.configuration = mappedStatement.getConfiguration();
  3. this.executor = executor;
  4. this.mappedStatement = mappedStatement;
  5. this.rowBounds = rowBounds;
  6.  
  7. this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
  8. this.objectFactory = configuration.getObjectFactory();
  9.  
  10. if (boundSql == null) { // issue #435, get the key before calculating the statement
  11. generateKeys(parameterObject);
  12. boundSql = mappedStatement.getBoundSql(parameterObject);
  13. }
  14.  
  15. this.boundSql = boundSql;
  16. //都说是相当于注册参数处理器,结果集处理器了。下面看默认的参数处理器是啥
  17. this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
  18. 18 this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
  19. }
  1. public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
    //可以看出来就是从mappenStatement的语言注册器创建参数处理器。实际上就一个语言处理器。
  2. ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
  3. parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
  4. return parameterHandler;
  5. }

默认的就是XMLLanguageDriver

  1. public class XMLLanguageDriver implements LanguageDriver {
  2.  
  3. @Override
  4. public ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
  5. return new DefaultParameterHandler(mappedStatement, parameterObject, boundSql);
  6. }

接下来就看DefaultParameterHandler怎么实现setParameters()

  1. @Override
  2. public void setParameters(PreparedStatement ps) {
  3. ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
  4. List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
  5. if (parameterMappings != null) {
  6. for (int i = 0; i < parameterMappings.size(); i++) {
  7. ParameterMapping parameterMapping = parameterMappings.get(i);
  8. if (parameterMapping.getMode() != ParameterMode.OUT) {
  9. Object value;
  10. String propertyName = parameterMapping.getProperty();
  11. if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
  12. value = boundSql.getAdditionalParameter(propertyName);
  13. } else if (parameterObject == null) {
  14. value = null;
  15. } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
  16. value = parameterObject;
  17. } else {
  18. MetaObject metaObject = configuration.newMetaObject(parameterObject);
  19. value = metaObject.getValue(propertyName);
  20. }
  21. TypeHandler typeHandler = parameterMapping.getTypeHandler();
  22. JdbcType jdbcType = parameterMapping.getJdbcType();
  23. if (value == null && jdbcType == null) {
    //这里有bug 如果传入值为0 也没设置参数jdbctype 会报错,这块可以给根据javaType给默认的类型
  24. jdbcType = configuration.getJdbcTypeForNull();
  25. }
  26. try {
  27. typeHandler.setParameter(ps, i + 1, value, jdbcType);
  28. } catch (TypeException e) {
  29. throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
  30. } catch (SQLException e) {
  31. throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
  32. }
  33. }
  34. }
  35. }
  36. }

这块就很简单了 根据每个参数JavaType jdbctype设设置。到此为止 prepareStatement的参数就都设置完了。

来看下 查询return handler.<E>query(stmt, resultHandler);

实际上也是PreparedStatementHandler实现的

  1. @Override
  2. public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
  3. PreparedStatement ps = (PreparedStatement) statement;
  4. ps.execute();
    //执行就不说了,就看下面 使用结果处理器来处理结果集 返回一个List
  5. return resultSetHandler.<E> handleResultSets(ps);
  6. }

resultSetHandler在父类构造器初始化的。看下默认的是什么吧

  1. public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
  2. ResultHandler resultHandler, BoundSql boundSql) {
  3. 3 ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
  4. resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
  5. return resultSetHandler;
  6. }
  1. public List<Object> handleResultSets(Statement stmt) throws SQLException {
  2. ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
  3.  
  4. final List<Object> multipleResults = new ArrayList<Object>();
  5.  
  6. int resultSetCount = 0;
    //ResultSet的包装类ResultSet,同时获取数据库的MetaData数据,包括数据表列名、列的类型、类序号等
  7. ResultSetWrapper rsw = getFirstResultSet(stmt);
  8.  
  9. List<ResultMap> resultMaps = mappedStatement.getResultMaps();
  10. int resultMapCount = resultMaps.size();
  11. validateResultMapsCount(rsw, resultMapCount);
  12. while (rsw != null && resultMapCount > resultSetCount) {
  13. ResultMap resultMap = resultMaps.get(resultSetCount);
  14. 14 handleResultSet(rsw, resultMap, multipleResults, null);
  15. rsw = getNextResultSet(stmt);
  16. cleanUpAfterHandlingResultSet();
  17. resultSetCount++;
  18. }
  19.  
  20. String[] resultSets = mappedStatement.getResulSets();
  21. if (resultSets != null) {
  22. while (rsw != null && resultSetCount < resultSets.length) {
  23. ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
  24. if (parentMapping != null) {
  25. String nestedResultMapId = parentMapping.getNestedResultMapId();
  26. ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
  27. handleResultSet(rsw, resultMap, null, parentMapping);
  28. }
  29. rsw = getNextResultSet(stmt);
  30. cleanUpAfterHandlingResultSet();
  31. resultSetCount++;
  32. }
  33. }
  34.  
  35. return collapseSingleResultList(multipleResults);
  36. }
  1. private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
  2. try {
  3. if (parentMapping != null) {
  4. 4 handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
  5. } else {
  6. if (resultHandler == null) {
  7. DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
  8. 8 handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
  9. multipleResults.add(defaultResultHandler.getResultList());
  10. } else {
  11. handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
  12. }
  13. }
  14. } finally {
  15. // issue #228 (close resultsets)
  16. closeResultSet(rsw.getResultSet());
  17. }
  18. }
  1. private void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
  2. if (resultMap.hasNestedResultMaps()) {
  3. ensureNoRowBounds();
  4. checkResultHandler();
    //嵌套结果集
  5. handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
  6. } else {
    //简单的结果集
  7. handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
  8. }
  9. }
  1. private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
  2. throws SQLException {
  3. DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();
  4. skipRows(rsw.getResultSet(), rowBounds);
  5. while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
  6. ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
  7. Object rowValue = getRowValue(rsw, discriminatedResultMap); //获取每一行的值
  8. storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
  9. }
  10. }
  1. private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {
  2. final ResultLoaderMap lazyLoader = new ResultLoaderMap();
    //创建数据对象的类对象 //todo这一块好复杂,有时间但单独在分析。
  3. Object resultObject = createResultObject(rsw, resultMap, lazyLoader, null);
  4. if (resultObject != null && !typeHandlerRegistry.hasTypeHandler(resultMap.getType())) {
  5. final MetaObject metaObject = configuration.newMetaObject(resultObject);
  6. boolean foundValues = !resultMap.getConstructorResultMappings().isEmpty();
  7. if (shouldApplyAutomaticMappings(resultMap, false)) {
    //这一块就是为这个对象挨个赋值了
  8. foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;
  9. }
  10. foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;
  11. foundValues = lazyLoader.size() > 0 || foundValues;
  12. resultObject = foundValues ? resultObject : null;
  13. return resultObject;
  14. }
  15. return resultObject;
  16. }
  1. private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
  2. List<UnMappedColumAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
  3. boolean foundValues = false;
  4. if (autoMapping.size() > 0) {
    //遍历表的每一项 给对象赋值。
  5. for (UnMappedColumAutoMapping mapping : autoMapping) {
    //根据对应的java类型调用不同getResult获取值 如String, getString(); Int getInt()
  6. final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);
  7. // issue #377, call setter on nulls
  8. if (value != null || configuration.isCallSettersOnNulls()) {
  9. if (value != null || !mapping.primitive) {
  10. metaObject.setValue(mapping.property, value);
  11. }
  12. foundValues = true;
  13. }
  14. }
  15. }
  16. return foundValues;
  17. }

到此为止,整个过程结束,结果集封装理解不是特别多,还有就是其中一些细节要以后慢慢推敲。如果有的地方解释的不对的地方希望看到的能及时提出探讨,万分感谢

Mybatis之是如何执行你的SQL的(SQL执行过程,参数解析过程,结果集封装过程)的更多相关文章

  1. 原!!mybatis如何直接 执行传入的任意sql语句 并按照顺序取出查询的结果集

    需求: 1.直接执行前端传来的任何sql语句,parameterType="String", 2.对于任何sql语句,其返回值类型无法用resultMap在xml文件里配置或者返回 ...

  2. mybatis下使用log4j打印sql语句和执行结果

    转载自:https://www.cnblogs.com/jeevan/p/3493972.html 本来以为很简单的问题, 结果自己搞了半天还是不行; 然后google, baidu, 搜出来各种方法 ...

  3. [转]mybatis如何直接 执行传入的任意sql语句 并按照顺序取出查询的结果集

    原文地址:https://www.cnblogs.com/wuyun-blog/p/5769096.html 需求: 1.直接执行前端传来的任何sql语句,parameterType="St ...

  4. mybatis如何直接 执行传入的任意sql语句 并按照顺序取出查询的结果集

    需求: 1.直接执行前端传来的任何sql语句,parameterType="String", 2.对于任何sql语句,其返回值类型无法用resultMap在xml文件里配置或者返回 ...

  5. 初看Mybatis 源码 (三) SQL是怎么执行的

    前面说到Java动态代理,Mybatis通过这种方式实现了我们通过getMapper方式得到的Dao接口,可以直接通过接口的没有实现的方法来执行sql. AuthUserDao mapper = se ...

  6. 【mybatis】service层中一个方法中使用mybatis进行数据库的 多个修改操作,可能是update也可能是delete操作,但是sql语句命名执行并且在控制台打印出来了,但是数据库中未更新到数据【事务的问题】

    问题描述: service层中一个方法中使用mybatis进行数据库的 多个修改操作,可能是update也可能是delete操作,但是sql语句命名执行并且在控制台打印出来了,但是数据库中未更新到数据 ...

  7. 面试官问你MyBatis SQL是如何执行的?把这篇文章甩给他

    初识 MyBatis MyBatis 是第一个支持自定义 SQL.存储过程和高级映射的类持久框架.MyBatis 消除了大部分 JDBC 的样板代码.手动设置参数以及检索结果.MyBatis 能够支持 ...

  8. MyBatis学习(一)---配置文件,Mapper接口和动态SQL

    MyBatis MyBatis官方学习网站 http://www.mybatis.org/mybatis-3/zh/index.html 为什么需要MyBatis? Jdbc操作数据库的不足之处 1. ...

  9. Java Persistence with MyBatis 3(中文版) 第三章 使用XML配置SQL映射器

    关系型数据库和SQL是经受时间考验和验证的数据存储机制.和其他的ORM 框架如Hibernate不同,MyBatis鼓励开发者可以直接使用数据库,而不是将其对开发者隐藏,因为这样可以充分发挥数据库服务 ...

随机推荐

  1. WCF WS-Security and WSE Nonce Authentication【转】

    原文:http://weblog.west-wind.com/posts/2012/Nov/24/WCF-WSSecurity-and-WSE-Nonce-Authentication?utm_sou ...

  2. 利用Web Services开发分布式应用

    一.引言 在前面文章中分别介绍了MSMQ和.NET Remoting技术,今天继续分享.NET 平台下另一种分布式技术——Web Services 二.Web Services 详细介绍 2.1 We ...

  3. /etc/fstab和/etc/mtab

    一./etc/fstab和/etc/mtab的区别 1./etc/fstab /etc/fstab是开机自动挂载的配置文件,在开机时起作用.相当于启动linux的时候,自动使用检查分区的fsck命令和 ...

  4. Spring Boot 报错:Error creating bean with name 'entityManagerFactory' defined in class path resource

    spring boot 写一个web项目,在使用spring-data-jpa的时候,启动报如下错误: Error starting ApplicationContext. To display th ...

  5. Hive之 数据类型

    hive 目前支持的数据类型如下: -- 数值类型 Numeric TypesTINYINT (1-byte signed integer, from -128 to 127)SMALLINT (2- ...

  6. docker默认配置文件不存在问题解决

    Docker默认的配置文件/etc/default/docker或者/etc/sysconfig/docker都不起作用,查看了一下/lib/systemd/system/docker.service ...

  7. bzoj3143游走

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3143 学到了无向图中点被经过的期望次数和边被经过的期望次数. 一个点被经过的期望次数  就是 ...

  8. 【python】 使用 setuptools

    不会安装python的egg文件,在网上搜索了一下,被“蟒蛇蛋”这个词雷到了,记录下. 随着对python的逐渐使用,发现一些python组件是用一个包管理器发布的,今天搞了快一个小时,终于搞定了,这 ...

  9. 安装memcached服务 和 php 安装memcache扩展

    这是所有的命令,至于哪个命令是干嘛的自己悟去吧  ,顺便穿插一些知识点 安装libevent cd /home/ wget  http://www.monkey.org/~provos/libeven ...

  10. Bootstrap-CL:面板

    ylbtech-Bootstrap-CL:面板 1.返回顶部 1. Bootstrap 面板(Panels) 本章将讲解 Bootstrap 面板(Panels).面板组件用于把 DOM 组件插入到一 ...