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小时内删除。
发表评论