MyBatis工作原理
本文转载自:https://blog.csdn.net/u014297148/article/details/78696096
1、MyBatis的架构
MyBatis的架构分层
MyBatis的实现原理
mybatis底层还是采用原生jdbc来对数据库进行操作的,只是通过 SqlSessionFactory,SqlSession Executor,StatementHandler,ParameterHandler,ResultHandler和TypeHandler等几个处理器封装了这些过程。
1、执行器:Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed);
2、参数处理器: ParameterHandler (getParameterObject, setParameters);
3、结构处理器: ResultSetHandler (handleResultSets, handleOutputParameters);
4、sql查询处理器:StatementHandler (prepare, parameterize, batch, update, query)
其中StatementHandler通过ParameterHandler与ResultHandler分别进行参数预编译与结果处理。而ParameterHandler与ResultHandler都使用TypeHandler进行映射。如下图:
2、MyBatis工作过程
首先在MyBatis启动的时候会去解析配置文件,包括全局配置文件和映射器配置文件,这里面包含了我们怎么控制MyBatis的行为,和我们要对数据库下达的指令,也就是我们的sql信息,我们会把它解析成一个Configuration对象。
接下来就是我们操作数据库的接口,它在应用程序和数据库中间,代表我们跟数据库之间的一次连接:这个就是SqlSession对象。
我们要获得一个会话,必须有一个会话工厂SqlSessionFactory,SqlSessionFactory里面又必须包含我们的所有的配置信息,所以我们会通过一个Builder来创建工厂类。
我们知道,Mybatis是对JDBC的封装,也就是意味着底层一定会出现JDBC的一些核心对象,比如执行SQL的Statement,结果集ResultSet。在MyBatis里面,SqlSession只是提供给应用的一个接口,还不是SQL的真正的执行对象。
通过看源码可以知道,SqlSession的子类DefaultSqlSession持有了一个Executor对象,用来封装对数据库的操作。在执行器Executor执行query或者update操作的时候,我们会创建一系列的对象,来处理参数、执行SQL、处理结果集,这里我们把它简化成一个对象StatementHandler。
这个就是MyBatis的工作流程,如图:
通过读mybatis的源码进行分析mybatis执行操作的整个过程,我们通过debug调试就可以知道Mybatis每一步做了什么事,我先把debug每一步结果截图,然后再分析这个流程。
第一步:读取配置文件,形成InputStream。
2.1、创建SqlSessionFactory的过程
从debug调试可以看出,返回的SqlSessionFactory是DefaultSqlSessionFactory类型的,但是Configuration此时已经被初始化了。查看源码后画下创建DefaultSqlSessionFactory的时序图:
2.2、创建SqlSession的过程
从debug调试看出,SqlSessionFactory.openSession()返回的SqlSession是DefaultSqlSession类型的,此SqlSession里包含一个Configuration对象和一个Executor对象。查看源码后画下创建DefaultSqlSession的时序图:
2.3、创建Mapper的过程
从debug调试可以看出,mapper是一个Mapper代理对象,而且初始化了Configuration对象、Executor对象。查看源码后画下创建Mapper的时序图:
2.4、执行CRUD过程
2.4.1、以select为例查看各步执行的源码
1、mapper.selectEmployeeList()其实是MapperProxy执行invoke方法,此方法先是判断Method的方法是不是Object的toString()等方法,如果不是就执行MapperMethod
1 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 2 try { 3 // 判断Method的方法是不是Object的toString等方法 4 if (Object.class.equals(method.getDeclaringClass())) { 5 return method.invoke(this, args); 6 } else if (isDefaultMethod(method)) { 7 return invokeDefaultMethod(proxy, method, args); 8 } 9 } catch (Throwable t) { 10 throw ExceptionUtil.unwrapThrowable(t); 11 } 12 // 判断private final Map<Method, MapperMethod> methodCache;这个map里面有没有这个方法的一级缓存 13 final MapperMethod mapperMethod = cachedMapperMethod(method); 14 return mapperMethod.execute(sqlSession, args); 15 } 16 17 private MapperMethod cachedMapperMethod(Method method) { 18 MapperMethod mapperMethod = methodCache.get(method); 19 if (mapperMethod == null) { 20 mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()); 21 methodCache.put(method, mapperMethod); 22 } 23 return mapperMethod; 24 }
经过上面的调用后进入MapperMethod里面执行
1 //判断sql命令类型 2 public Object execute(SqlSession sqlSession, Object[] args) { 3 Object param; 4 Object result; 5 if(SqlCommandType.INSERT == this.command.getType()) { 6 param = this.method.convertArgsToSqlCommandParam(args); 7 result = this.rowCountResult(sqlSession.insert(this.command.getName(), param)); 8 } else if(SqlCommandType.UPDATE == this.command.getType()) { 9 param = this.method.convertArgsToSqlCommandParam(args); 10 result = this.rowCountResult(sqlSession.update(this.command.getName(), param)); 11 } else if(SqlCommandType.DELETE == this.command.getType()) { 12 param = this.method.convertArgsToSqlCommandParam(args); 13 result = this.rowCountResult(sqlSession.delete(this.command.getName(), param)); 14 } else if(SqlCommandType.SELECT == this.command.getType()) { 15 //我们测试的是select类型,则再判断这个方法的返回类型 16 if(this.method.returnsVoid() && this.method.hasResultHandler()) { 17 this.executeWithResultHandler(sqlSession, args); 18 result = null; 19 } else if(this.method.returnsMany()) { 20 //我们是查询列表,此方法执行 21 result = this.executeForMany(sqlSession, args); 22 } else if(this.method.returnsMap()) { 23 result = this.executeForMap(sqlSession, args); 24 } else { 25 param = this.method.convertArgsToSqlCommandParam(args); 26 result = sqlSession.selectOne(this.command.getName(), param); 27 } 28 } else { 29 if(SqlCommandType.FLUSH != this.command.getType()) { 30 throw new BindingException("Unknown execution method for: " + this.command.getName()); 31 } 32 result = sqlSession.flushStatements(); 33 } 34 if(result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) { 35 throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ")."); 36 } else { 37 return result; 38 } 39 } 40 41 private <E> Object executeForMany(SqlSession sqlSession, Object[] args) { 42 //将param做处理 自动处理为param1,param2.. 43 Object param = this.method.convertArgsToSqlCommandParam(args); 44 List result; 45 if(this.method.hasRowBounds()) { 46 RowBounds rowBounds = this.method.extractRowBounds(args); 47 //调用该对象的DefaultSqlSession的selectList方法 48 result = sqlSession.selectList(this.command.getName(), param, rowBounds); 49 } else { 50 result = sqlSession.selectList(this.command.getName(), param); 51 } 52 return !this.method.getReturnType().isAssignableFrom(result.getClass())?(this.method.getReturnType().isArray()?this.convertToArray(result):this.convertToDeclaredCollection(sqlSession.getConfiguration(), result)):result; 53 } 54 55 //处理参数方法 56 public Object convertArgsToSqlCommandParam(Object[] args) { 57 int paramCount = this.params.size(); 58 if(args != null && paramCount != 0) { 59 if(!this.hasNamedParameters && paramCount == 1) { 60 return args[((Integer)this.params.keySet().iterator().next()).intValue()]; 61 } else { 62 Map<String, Object> param = new MapperMethod.ParamMap(); 63 int i = 0; 64 for(Iterator i$ = this.params.entrySet().iterator(); i$.hasNext(); ++i) { 65 Entry<Integer, String> entry = (Entry)i$.next(); 66 param.put(entry.getValue(), args[((Integer)entry.getKey()).intValue()]); 67 String genericParamName = "param" + String.valueOf(i + 1); 68 if(!param.containsKey(genericParamName)) { 69 param.put(genericParamName, args[((Integer)entry.getKey()).intValue()]); 70 } 71 } 72 return param; 73 } 74 } else { 75 return null; 76 } 77 }
调用DefaultSqlSession的selectList()方法
1 public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) { 2 List var5; 3 try { 4 //获取MappedStatement对象 5 MappedStatement ms = this.configuration.getMappedStatement(statement); 6 //调用cachingExecutor执行器的方法 7 var5 = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER); 8 } catch (Exception var9) { 9 throw ExceptionFactory.wrapException("Error querying database. Cause: " + var9, var9); 10 } finally { 11 ErrorContext.instance().reset(); 12 } 13 return var5; 14 } 15 16 //CachingExector的query方法 17 public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { 18 BoundSql boundSql = ms.getBoundSql(parameterObject); 19 CacheKey key = this.createCacheKey(ms, parameterObject, rowBounds, boundSql); 20 return this.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); 21 } 22 23 public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { 24 Cache cache = ms.getCache(); 25 if(cache != null) { 26 this.flushCacheIfRequired(ms); 27 if(ms.isUseCache() && resultHandler == null) { 28 this.ensureNoOutParams(ms, parameterObject, boundSql); 29 List<E> list = (List)this.tcm.getObject(cache, key); 30 if(list == null) { 31 //这里是调用Executor里的query方法 如果开启了缓存这掉CachingExecutor的 如果没有则是调用BaseExecutor的 32 list = this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); 33 this.tcm.putObject(cache, key, list); 34 } 35 36 return list; 37 } 38 } 39 return this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); 40 }
BaseExecutor的query方法
1 public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { 2 BoundSql boundSql = ms.getBoundSql(parameter); 3 CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql); 4 return query(ms, parameter, rowBounds, resultHandler, key, boundSql); 5 } 6 7 public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { 8 ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId()); 9 if (closed) { 10 throw new ExecutorException("Executor was closed."); 11 } 12 if (queryStack == 0 && ms.isFlushCacheRequired()) { 13 clearLocalCache(); 14 } 15 List<E> list; 16 try { 17 queryStack++; 18 list = resultHandler == null ? (List<E>) localCache.getObject(key) : null; 19 if (list != null) { 20 handleLocallyCachedOutputParameters(ms, key, parameter, boundSql); 21 } else { 22 list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql); 23 } 24 } finally { 25 queryStack--; 26 } 27 if (queryStack == 0) { 28 for (DeferredLoad deferredLoad : deferredLoads) { 29 deferredLoad.load(); 30 } 31 // issue #601 32 deferredLoads.clear(); 33 if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) { 34 // issue #482 35 clearLocalCache(); 36 } 37 } 38 return list; 39 } 40 41 private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { 42 List<E> list; 43 localCache.putObject(key, EXECUTION_PLACEHOLDER); 44 try { 45 list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql); 46 } finally { 47 localCache.removeObject(key); 48 } 49 localCache.putObject(key, list); 50 if (ms.getStatementType() == StatementType.CALLABLE) { 51 localOutputParameterCache.putObject(key, parameter); 52 } 53 return list; 54 }
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(); 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 } 12 13 private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException { 14 Statement stmt; 15 Connection connection = getConnection(statementLog); 16 stmt = handler.prepare(connection, transaction.getTimeout()); 17 handler.parameterize(stmt); 18 return stmt; 19 }
ParameterHandler参数处理器的方法
1 public interface ParameterHandler { 2 Object getParameterObject(); 3 //此方法是用DefaultParameterHandler实现的 4 void setParameters(PreparedStatement var1) throws SQLException; 5 }
DefaultParameterHandler默认参数处理器的方法
public void setParameters(PreparedStatement ps) { ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId()); List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); if (parameterMappings != null) { for (int i = 0; i < parameterMappings.size(); i++) { ParameterMapping parameterMapping = parameterMappings.get(i); if (parameterMapping.getMode() != ParameterMode.OUT) { Object value; String propertyName = parameterMapping.getProperty(); if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params value = boundSql.getAdditionalParameter(propertyName); } else if (parameterObject == null) { value = null; } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { value = parameterObject; } else { MetaObject metaObject = configuration.newMetaObject(parameterObject); value = metaObject.getValue(propertyName); } // 这里用调用 TypeHandler类型映射处理器来映射 TypeHandler typeHandler = parameterMapping.getTypeHandler(); JdbcType jdbcType = parameterMapping.getJdbcType(); if (value == null && jdbcType == null) { jdbcType = configuration.getJdbcTypeForNull(); } try { // 类型处理器设置参数映射 typeHandler.setParameter(ps, i + 1, value, jdbcType); } catch (TypeException e) { throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e); } catch (SQLException e) { throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e); } } } } }
SimpleStatementHandler的query()方法:
1 public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException { 2 String sql = boundSql.getSql(); 3 statement.execute(sql); 4 return resultSetHandler.<E>handleResultSets(statement); 5 }
最后一句resultSetHandler.<E>handleResultSets(statement)调用的是子类DefaultResultSetHandler的handleResultSets:
1 public List<Object> handleResultSets(Statement stmt) throws SQLException { 2 ErrorContext.instance().activity("handling results").object(this.mappedStatement.getId()); 3 List<Object> multipleResults = new ArrayList(); 4 int resultSetCount = 0; 5 ResultSetWrapper rsw = this.getFirstResultSet(stmt); 6 List<ResultMap> resultMaps = this.mappedStatement.getResultMaps(); 7 int resultMapCount = resultMaps.size(); 8 this.validateResultMapsCount(rsw, resultMapCount); 9 while(rsw != null && resultMapCount > resultSetCount) { 10 ResultMap resultMap = (ResultMap)resultMaps.get(resultSetCount); 11 this.handleResultSet(rsw, resultMap, multipleResults, (ResultMapping)null); 12 rsw = this.getNextResultSet(stmt); 13 this.cleanUpAfterHandlingResultSet(); 14 ++resultSetCount; 15 } 16 String[] resultSets = this.mappedStatement.getResulSets(); 17 if(resultSets != null) { 18 while(rsw != null && resultSetCount < resultSets.length) { 19 ResultMapping parentMapping = (ResultMapping)this.nextResultMaps.get(resultSets[resultSetCount]); 20 if(parentMapping != null) { 21 String nestedResultMapId = parentMapping.getNestedResultMapId(); 22 ResultMap resultMap = this.configuration.getResultMap(nestedResultMapId); 23 this.handleResultSet(rsw, resultMap, (List)null, parentMapping); 24 } 25 rsw = this.getNextResultSet(stmt); 26 this.cleanUpAfterHandlingResultSet(); 27 ++resultSetCount; 28 } 29 } 30 return this.collapseSingleResultList(multipleResults); 31 } 32 33 //处理结果集 34 private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException { 35 try { 36 if(parentMapping != null) { 37 this.handleRowValues(rsw, resultMap, (ResultHandler)null, RowBounds.DEFAULT, parentMapping); 38 } else if(this.resultHandler == null) { 39 DefaultResultHandler defaultResultHandler = new DefaultResultHandler(this.objectFactory); 40 this.handleRowValues(rsw, resultMap, defaultResultHandler, this.rowBounds, (ResultMapping)null); 41 multipleResults.add(defaultResultHandler.getResultList()); 42 } else { 43 this.handleRowValues(rsw, resultMap, this.resultHandler, this.rowBounds, (ResultMapping)null); 44 } 45 } finally { 46 this.closeResultSet(rsw.getResultSet()); 47 } 48 } 49 50 private void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException { 51 if(resultMap.hasNestedResultMaps()) { 52 this.ensureNoRowBounds(); 53 this.checkResultHandler(); 54 this.handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping); 55 } else { 56 this.handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping); 57 } 58 } 59 60 private void handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException { 61 DefaultResultContext<Object> resultContext = new DefaultResultContext(); 62 this.skipRows(rsw.getResultSet(), rowBounds); 63 Object rowValue = null; 64 while(this.shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) { 65 ResultMap discriminatedResultMap = this.resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, (String)null); 66 CacheKey rowKey = this.createRowKey(discriminatedResultMap, rsw, (String)null); 67 Object partialObject = this.nestedResultObjects.get(rowKey); 68 if(this.mappedStatement.isResultOrdered()) { 69 if(partialObject == null && rowValue != null) { 70 this.nestedResultObjects.clear(); 71 this.storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet()); 72 } 73 //获取行的值 74 rowValue = this.getRowValue(rsw, discriminatedResultMap, rowKey, (String)null, partialObject); 75 } else { 76 rowValue = this.getRowValue(rsw, discriminatedResultMap, rowKey, (String)null, partialObject); 77 if(partialObject == null) { 78 this.storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet()); 79 } 80 } 81 } 82 if (rowValue != null && mappedStatement.isResultOrdered() && shouldProcessMoreRows(resultContext, rowBounds)) { 83 storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet()); 84 previousRowValue = null; 85 } else if (rowValue != null) { 86 previousRowValue = rowValue; 87 } 88 } 89 90 private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, CacheKey combinedKey, String columnPrefix, Object partialObject) throws SQLException { 91 final String resultMapId = resultMap.getId(); 92 Object rowValue = partialObject; 93 if (rowValue != null) { 94 final MetaObject metaObject = configuration.newMetaObject(rowValue); 95 putAncestor(rowValue, resultMapId); 96 applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, false); 97 ancestorObjects.remove(resultMapId); 98 } else { 99 final ResultLoaderMap lazyLoader = new ResultLoaderMap(); 100 rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix); 101 if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) { 102 final MetaObject metaObject = configuration.newMetaObject(rowValue); 103 boolean foundValues = this.useConstructorMappings; 104 if (shouldApplyAutomaticMappings(resultMap, true)) { 105 foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues; 106 } 107 foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues; 108 putAncestor(rowValue, resultMapId); 109 foundValues = applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, true) || foundValues; 110 ancestorObjects.remove(resultMapId); 111 foundValues = lazyLoader.size() > 0 || foundValues; 112 rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null; 113 } 114 if (combinedKey != CacheKey.NULL_CACHE_KEY) { 115 nestedResultObjects.put(combinedKey, rowValue); 116 } 117 } 118 return rowValue; 119 } 120 121 private boolean shouldApplyAutomaticMappings(ResultMap resultMap, boolean isNested) { 122 return resultMap.getAutoMapping() != null?resultMap.getAutoMapping().booleanValue():(isNested?AutoMappingBehavior.FULL == this.configuration.getAutoMappingBehavior():AutoMappingBehavior.NONE != this.configuration.getAutoMappingBehavior()); 123 } 124 125 private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException { 126 List<DefaultResultSetHandler.UnMappedColumAutoMapping> autoMapping = this.createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix); 127 boolean foundValues = false; 128 if(autoMapping.size() > 0) { 129 Iterator i$ = autoMapping.iterator(); 130 while(true) { 131 //这里使用了内部类对参数和结果集进行映射 132 DefaultResultSetHandler.UnMappedColumAutoMapping mapping; 133 Object value; 134 do { 135 if(!i$.hasNext()) { 136 return foundValues; 137 } 138 mapping = (DefaultResultSetHandler.UnMappedColumAutoMapping)i$.next(); 139 value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column); 140 } while(value == null && !this.configuration.isCallSettersOnNulls()); 141 if(value != null || !mapping.primitive) { 142 metaObject.setValue(mapping.property, value); 143 } 144 foundValues = true; 145 } 146 } else { 147 return foundValues; 148 } 149 } 150 private static class UnMappedColumAutoMapping { 151 private final String column; 152 private final String property; 153 private final TypeHandler<?> typeHandler; 154 private final boolean primitive; 155 //此处才类型器对结果进行映射 156 public UnMappedColumAutoMapping(String column, String property, TypeHandler<?> typeHandler, boolean primitive) { 157 this.column = column; 158 this.property = property; 159 this.typeHandler = typeHandler; 160 this.primitive = primitive; 161 } 162 }