Mybatis之是如何执⾏你的SQL的(SQL执⾏过程,参数解析过程,结果集封
装过程)
Myabtis的SQL的执⾏是通过SqlSession。默认的实现类是DefalutSqlSession。通过源码可以发现,selectOne最终会调⽤selectList这个⽅法。
1  @Override
2public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
3try {
     //获取MappedStatement  通过id 到configuration⾥⾯
4      MappedStatement ms = MappedStatement(statement);
5return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
6    } catch (Exception e) {
7throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
8    } finally {
9      ErrorContext.instance().reset();
10    }
11  }
通过上⾯可以发现是通过Executor去执⾏查询。但是executor是个接⼝,是什么时候指定的⽤什么执⾏器呢。
因为SqlSession是通过SqlSessionFactory接⼝获取的,实现类是DefaultSqlSessionFactory
1private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
2    Transaction tx = null;
3try {
4final Environment environment = Environment();
5final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
6      tx = DataSource(), level, autoCommit);
7final Executor executor = wExecutor(tx, execType);
8return new DefaultSqlSession(configuration, executor, autoCommit);
9    } catch (Exception e) {
10      closeTransaction(tx); // may have fetched a connection so lets call close()
11throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
12    } finally {
13      ErrorContext.instance().reset();
14    }
15  }
1public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
2    executorType = executorType == null ? defaultExecutorType : executorType;
3    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
4    Executor executor;
5if (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    }
12if (cacheEnabled) {
13      executor = new CachingExecutor(executor);
14    }
15    executor = (Executor) interceptorChain.pluginAll(executor);
16return executor;
17  }
可以看到默认的是SimpleExecutor;然后默认的是开启缓存的,所以最终应该是⼀个CachingExecutor,但是CachingExecutor有⼀个构造器参数是前⾯的执⾏器。
这是⼀种典型的装饰器设计模式
下⾯那⾏代码你现在只需要知道如果有Executor的,就会返回⼀个代理对象,在执⾏executor⽅法前,会执⾏。这是动态代理。
后⾯讲Myabtis原理的时候会详细介绍。
这下知道了是CachingExecotor,来看下CachingExecutor⽅法;
1public <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);
4return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
5  }
①先看是如何获取BoundSql  这个对象,包含了sql,params等信息。
1public BoundSql getBoundSql(Object parameterObject) {
2    BoundSql boundSql = BoundSql(parameterObject);
3    List<ParameterMapping> parameterMappings = ParameterMappings();
4if (parameterMappings == null || parameterMappings.isEmpty()) {
5      boundSql = new BoundSql(configuration, Sql(), ParameterMappings(), parameterObject);
6    }
7
8// check for nested result maps in parameter mappings (issue #30)
9for (ParameterMapping pm : ParameterMappings()) {
10      String rmId = pm.getResultMapId();
11if (rmId != null) {
12        ResultMap rm = ResultMap(rmId);
13if (rm != null) {
14          hasNestedResultMaps |= rm.hasNestedResultMaps();
15        }
16      }
17    }
可以发现从sqlSource中获取BoundSql
⼀,DynamicSqlSourcre
1public class DynamicSqlSource implements SqlSource {
2
3private Configuration configuration;
4private SqlNode rootSqlNode;
5
6public DynamicSqlSource(Configuration configuration, SqlNode rootSqlNode) {
9  }
error parse new10
11  @Override
12public BoundSql getBoundSql(Object parameterObject) {
这⼀块的操作就是替换sql⾥⾯${}部分
13DynamicContext context = new DynamicContext(configuration, parameterObject);
14    rootSqlNode.apply(context);
15    SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
16    Class<?> parameterType = parameterObject == null ? Object.class : Class();
17    SqlSource sqlSource = sqlSourceParser.Sql(), parameterType, Bindings());
18    BoundSql boundSql = BoundSql(parameterObject);
19for (Map.Entry<String, Object> entry : Bindings().entrySet()) {
20      boundSql.Key(), Value());
21    }
22return boundSql;
23  }
24
25 }
来看下是如何替换sql的:
1public DynamicContext(Configuration configuration, Object parameterObject) {
2if (parameterObject != null && !(parameterObject instanceof Map)) {
//如果参数类型不是map则构造⼀个MetaObject; //todo 这⼀块⼲嘛的⽬前还不清楚,后⾯研究mybatis反射时候研究
//这个对象保存着Configuration的那个⼏个factory 反射factory 驼峰Factory,创建对象factory
3      MetaObject metaObject = wMetaObject(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, DatabaseId());
10  }
rootSqlNode.apply实际上接⼝的⽅法,这是根据节点的类别去执⾏,我们正常的MixedSqlNode实际上就是SqlNode数组类型,
这⾥只拿TextSqlNode做例⼦来看:
1  @Override
2public boolean apply(DynamicContext context) {
3    GenericTokenParser parser = createParser(new BindingTokenParser(context, injectionFilter));
4    context.appendSql(parser.parse(text));
5return true;
6  }
看过上⼀篇的应该对这段有了解,就是⽤具体解析类来解析节点内容来,parser获取${}中间变量的名字,然后BindingTokenParser去处理;parser.parses就是把sql⾥⾯每个${}替换成相应的值的作⽤
1public BindingTokenParser(DynamicContext context, Pattern injectionFilter) {
3this.injectionFilter = injectionFilter;
4    }
5
6    @Override
7public String handleToken(String content) {
//从参数对象⾥⾯获取值返回
8      Object parameter = Bindings().get("_parameter");
9if (parameter == null) {
10        Bindings().put("value", null);
//是不是基本类型
11      } else if (SimpleTypeRegistry.Class())) {
12        Bindings().put("value", parameter);
13      }
//获取到对应值,这⼀块很复杂,有时间在研究。
14Object value = Value(content, Bindings());
15      String srtValue = (value == null ? "" : String.valueOf(value)); // issue #274 return "" instead of "null"
16      checkInjection(srtValue);
17return srtValue;
18    }
19
20private void checkInjection(String value) {
21if (injectionFilter != null && !injectionFilter.matcher(value).matches()) {
22throw new ScriptingException("Invalid input. Please conform to regex" + injectionFilter.pattern());
23      }
24    }
25  }
好了到此为⽌ sql⾥⾯${}都已经替换成该有的值了,根据变量名获取Value这⼀块下回研究下在另外写篇⽂章。
然后看这段代码:
SqlSource sqlSource = sqlSourceParser.Sql(), parameterType, Bindings());
BoundSql boundSql = BoundSql(parameterObject);
这⼀段也很重要实际上是填充boundSql⾥⾯parameterMapping的
来看SqlSourceBuilder
1public 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);
5return new StaticSqlSource(configuration, sql, ParameterMappings());
6  }
这⼀块代码应该很熟悉了吧,实际上就是把#{}替换成?同时记录下参数的类型等信息,因为逻辑前⾯有介绍,直接看ParameterMappingTokenHandler的⽅法 1public String handleToken(String content) {
//记录参数
2      parameterMappings.add(buildParameterMapping(content));
//替换成?
3return "?";
4    }
5
6private ParameterMapping buildParameterMapping(String content) {
7      Map<String, String> propertiesMap = parseParameterMapping(content);
8      String property = ("property");
9      Class<?> propertyType;
10if (metaParameters.hasGetter(property)) { // issue #448 get type from additional params
11        propertyType = GetterType(property);
12      } else if (typeHandlerRegistry.hasTypeHandler(parameterType)) {
13        propertyType = parameterType;
14      } else if (JdbcType.CURSOR.name().("jdbcType"))) {
15        propertyType = java.sql.ResultSet.class;
16      } else if (property != null) {
17        MetaClass metaClass = MetaClass.forClass(parameterType, ReflectorFactory());
18if (metaClass.hasGetter(property)) {
19          propertyType = GetterType(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;
29for (Map.Entry<String, String> entry : Set()) {
30        String name = Key();
31        String value = Value();
32if ("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          de(resolveParameterMode(value));
39        } else if ("numericScale".equals(name)) {
40          builder.numericScale(Integer.valueOf(value));
41        } else if ("resultMap".equals(name)) {
42          sultMapId(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)) {
50throw new BuilderException("Expression based parameters are not supported yet");
51        } else {
52throw new BuilderException("An invalid property '" + name + "' was found in mapping #{" + content + "}.  Valid properties are " + parameterProperties);
53        }
54      }
55if (typeHandlerAlias != null) {
56        peHandler(resolveTypeHandler(javaType, typeHandlerAlias));
57      }
58return builder.build();
59    }
现在回过头开始看CachingExecutor的query⽅法了
1public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
2throws SQLException {
//这块就是mybatis的⼆级缓存
3    Cache cache = ms.getCache();
4if (cache != null) {
5      flushCacheIfRequired(ms);
6if (ms.isUseCache() && resultHandler == null) {
7        ensureNoOutParams(ms, parameterObject, boundSql);
8        @SuppressWarnings("unchecked")
9        List<E> list = (List<E>) Object(cache, key);
10if (list == null) {
11          list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
12          tcm.putObject(cache, key, list); // issue #578 and #116
13        }
14return list;
15      }
16    }
//最终调⽤的还是CachingExecutor⾥装饰的那个执⾏器
17return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
18  }
这个⽅法是所有执⾏器⽗类的BaseExecutor来实现的
1public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
2    ErrorContext.instance().Resource()).activity("executing a query").Id());
3if (closed) {
4throw new ExecutorException("Executor was closed.");
5    }
6if (queryStack == 0 && ms.isFlushCacheRequired()) {
7      clearLocalCache();
8    }
9    List<E> list;
10try {
11      queryStack++;
12      list = resultHandler == null ? (List<E>) Object(key) : null;
13if (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    }
21if (queryStack == 0) {
22for (DeferredLoad deferredLoad : deferredLoads) {
23        deferredLoad.load();
24      }
25// issue #601
26      deferredLoads.clear();
27if (LocalCacheScope() == LocalCacheScope.STATEMENT) {
28// issue #482
29        clearLocalCache();
30      }
31    }
32return list;
33  }
//这⾥应该就是mybatis的⼀级缓存,直接看从数据库查询数据
1private <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);
4try {
      //在⼦类中实现的 doQuery 查询出来结果放⼊⼀级缓存
5      list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
6    } finally {
7      veObject(key);
8    }
9    localCache.putObject(key, list);
10if (ms.getStatementType() == StatementType.CALLABLE) {
11      localOutputParameterCache.putObject(key, parameter);
12    }
13return list;
14  }
看SimpleExecutor的doQuery的实现
1public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
2    Statement stmt = null;
3try {
4      Configuration configuration = ms.getConfiguration();
//创建StatementHandler的代理对象,有的话返回代理对象,没有返回默认的RoutingStatmenthandler 典型的责任链模式
5      StatementHandler handler = wStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
6      stmt = prepareStatement(handler, ms.getStatementLog());
7return handler.<E>query(stmt, resultHandler);
8    } finally {
9      closeStatement(stmt);
10    }
11  }
接下来看下是怎么创建合适的Statement对象的,
1private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
2    Statement stmt;
3    Connection connection = getConnection(statementLog);
4    stmt = handler.prepare(connection);
5    handler.parameterize(stmt);//设置参数
6return stmt;
7  }
RoutingStatmenthandler
1 @Override
2public Statement prepare(Connection connection) throws SQLException {
3return delegate.prepare(connection);
4 }
5
6 @Override
7public void parameterize(Statement statement) throws SQLException {
8  delegate.parameterize(statement);
9 }
调⽤的都是装饰的statementHander ,delegate是在RoutingStatementHandler构造器初始化的;
1public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
2
3switch (ms.getStatementType()) {
4case STATEMENT:
5        delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
6break;
7case PREPARED:
8        delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandl
er, boundSql);
9break;
10case CALLABLE:
11        delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
12break;
13default:
14throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
15    }
16
17  }
可以看出来是根据ms保存的,三张就是Statement的三种,我们直接看预编译的,PreparedStatementHandler
实际上⼀些公共⽅法在BaseStatementHandler实现了
1public Statement prepare(Connection connection) throws SQLException {
2    ErrorContext.instance().Sql());
3    Statement statement = null;
4try {
5      statement = instantiateStatement(connection);
6      setStatementTimeout(statement);
7      setFetchSize(statement);
8return statement;
9    } catch (SQLException e) {
10      closeStatement(statement);
11throw e;
12    } catch (Exception e) {
13      closeStatement(statement);
14throw new ExecutorException("Error preparing statement.  Cause: " + e, e);
15    }
16  }
instantiateStatement⼦类PreparedStatementHandler实现
1protected Statement instantiateStatement(Connection connection) throws SQLException {
2    String sql = Sql();
3if (KeyGenerator() instanceof Jdbc3KeyGenerator) {
4      String[] keyColumnNames = KeyColumns();
5if (keyColumnNames == null) {
6return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
7      } else {
8return connection.prepareStatement(sql, keyColumnNames);
9      }
10    } else if (ResultSetType() != null) {
11return connection.prepareStatement(sql, ResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
12    } else {
13return connection.prepareStatement(sql);
14    }
15  }
上⾯就是根据mappedStatement的resultType不同创建不同构造器的Statement;
下⾯来看下参数是怎么设置的。PreparedStatementHandler,但是handler是⾥⾯的paramterHandler是什么实现类呢?什么时候注⼊的呢?
1public void parameterize(Statement statement) throws SQLException {
2    parameterHandler.setParameters((PreparedStatement) statement);
3  }
来看下BaseStatementHandler的构造器
1protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { figuration = Configuration();
4this.mappedStatement = mappedStatement;
6
8this.objectFactory = ObjectFactory();
9
10if (boundSql == null) { // issue #435, get the key before calculating the statement
11      generateKeys(parameterObject);
12      boundSql = BoundSql(parameterObject);
13    }
14
15this.boundSql = boundSql;
16    //都说是相当于注册参数处理器,结果集处理器了。下⾯看默认的参数处理器是啥
17  this.parameterHandler = wParameterHandler(mappedStatement, parameterObject, boundSql);
18    sultSetHandler = wResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
19  }
1public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
//可以看出来就是从mappenStatement的语⾔注册器创建参数处理器。实际上就⼀个语⾔处理器。
2    ParameterHandler parameterHandler = Lang().createParameterHandler(mappedStatement, parameterObject, boundSql);
3    parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
4return parameterHandler;
5  }
默认的就是XMLLanguageDriver
1public class XMLLanguageDriver implements LanguageDriver {
2
3  @Override
4public ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
5return new DefaultParameterHandler(mappedStatement, parameterObject, boundSql);
6  }
接下来就看DefaultParameterHandler怎么实现setParameters()
1  @Override
2public void setParameters(PreparedStatement ps) {
3    ErrorContext.instance().activity("setting parameters").ParameterMap().getId());
4    List<ParameterMapping> parameterMappings = ParameterMappings();

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。