02.24 Mybatis的工作原理

1.Mybatis的架構

1.1 Mybatis的框架分層


Mybatis的工作原理

1.2 MyBatis的實現原理

mybatis底層還是採用原生jdbc來對數據庫進行操作的,只是通過 SqlSessionFactory,SqlSession Executor,StatementHandler,ParameterHandler,ResultHandler和TypeHandler等幾個處理器封裝了這些過程

<code> 執行器:Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)   參數處理器: ParameterHandler (getParameterObject, setParameters)   結構處理器 ResultSetHandler (handleResultSets, handleOutputParameters)    sql查詢處理器:StatementHandler (prepare, parameterize, batch, update, query)/<code>

其中StatementHandler用通過ParameterHandler與ResultHandler分別進行參數預編譯 與結果處理。而ParameterHandler與ResultHandler都使用TypeHandler進行映射。如下圖:


Mybatis的工作原理

2.Mybatis工作過程

通過讀mybatis的源碼進行分析mybatis的執行操作的整個過程,我們通過debug調試就可以知道Mybatis每一步做了什麼事,我先把debug每一步結果 截圖,然後在分析這個流程。

第一步:讀取配置文件,形成InputStream

2.1 創建SqlSessionFacotry的過程


Mybatis的工作原理

從debug調試看出 返回的 sqlSessionFactory 是DefaultSesssionFactory類型的,但是configuration此時已經被初始化了。查看源碼後畫如下創建DefaultSessionFactory的時序圖:


Mybatis的工作原理

2.2 創建SqlSession的過程


Mybatis的工作原理

從debug調試 看出SqlSessinoFactory.openSession() 返回的sqlSession是 DefaultSession類型的,此SqlSession裡包含一個Configuration的對象,和一個Executor對象。查看源碼後畫如下創建DefaultSession的時序圖:


Mybatis的工作原理

2.3 創建Mapper的過程


Mybatis的工作原理

從debug調試可以看出,mapper是一個Mapper代理對象,而且初始化了Configuration對象,Executor的對象。查看源碼後畫如下創建Mapper的時序圖:


Mybatis的工作原理

2.4 執行CRUD過程

2.4.1 以select為例查看各步執行的源碼

1.mapper.selectEmployeeList()其實是MapperProxy執行invoke方法,此方法顯示是判斷Method的方法是不是Object的toString等方法如果不是就執行MapperMethod

<code>public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 判斷Method的方法是不是Object的toString等方法     if(Object.class.equals(method.getDeclaringClass())) {            try {                return method.invoke(this, args);            } catch (Throwable var5) {                throw ExceptionUtil.unwrapThrowable(var5);            }        } else {        //判斷private final Map<method> methodCache;這個map裡面有沒有這個方法的一級緩存,如果沒            MapperMethod mapperMethod = this.cachedMapperMethod(method);            return mapperMethod.execute(this.sqlSession, args);        }    }    //查詢一級緩存和設置一級緩存     private MapperMethod cachedMapperMethod(Method method) {        MapperMethod mapperMethod = (MapperMethod)this.methodCache.get(method);        if(mapperMethod == null) {            mapperMethod = new MapperMethod(this.mapperInterface, method, this.sqlSession.getConfiguration());            this.methodCache.put(method, mapperMethod);        }        return mapperMethod;    }/<method>/<code>

經過上面的調用後進入MapperMethod裡面執行

<code>//判斷sql命令類型public Object execute(SqlSession sqlSession, Object[] args) {        Object param;        Object result;        if(SqlCommandType.INSERT == this.command.getType()) {            param = this.method.convertArgsToSqlCommandParam(args);            result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));        } else if(SqlCommandType.UPDATE == this.command.getType()) {            param = this.method.convertArgsToSqlCommandParam(args);            result = this.rowCountResult(sqlSession.update(this.command.getName(), param));        } else if(SqlCommandType.DELETE == this.command.getType()) {            param = this.method.convertArgsToSqlCommandParam(args);            result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));        } else if(SqlCommandType.SELECT == this.command.getType()) {        //我們測試的是select類型,則再判斷這個方法的返回類型            if(this.method.returnsVoid() && this.method.hasResultHandler()) {                this.executeWithResultHandler(sqlSession, args);                result = null;            } else if(this.method.returnsMany()) {               //我們是查詢列表,此方法執行                result = this.executeForMany(sqlSession, args);            } else if(this.method.returnsMap()) {                result = this.executeForMap(sqlSession, args);            } else {                param = this.method.convertArgsToSqlCommandParam(args);                result = sqlSession.selectOne(this.command.getName(), param);            }        } else {            if(SqlCommandType.FLUSH != this.command.getType()) {                throw new BindingException("Unknown execution method for: " + this.command.getName());            }            result = sqlSession.flushStatements();        }        if(result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) {            throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ").");        } else {            return result;        }    }private  Object executeForMany(SqlSession sqlSession, Object[] args) {//將param做處理 自動處理為param1,param2..        Object param = this.method.convertArgsToSqlCommandParam(args);        List result;        if(this.method.hasRowBounds()) {            RowBounds rowBounds = this.method.extractRowBounds(args);            //調用該對象的DefaultSqlSession的selectList方法            result = sqlSession.selectList(this.command.getName(), param, rowBounds);        } else {            result = sqlSession.selectList(this.command.getName(), param);        }        return !this.method.getReturnType().isAssignableFrom(result.getClass())?(this.method.getReturnType().isArray()?this.convertToArray(result):this.convertToDeclaredCollection(sqlSession.getConfiguration(), result)):result;    }//處理參數方法 public Object convertArgsToSqlCommandParam(Object[] args) {            int paramCount = this.params.size();            if(args != null && paramCount != 0) {                if(!this.hasNamedParameters && paramCount == 1) {                    return args[((Integer)this.params.keySet().iterator().next()).intValue()];                } else {                    Map<string> param = new MapperMethod.ParamMap();                    int i = 0;                    for(Iterator i$ = this.params.entrySet().iterator(); i$.hasNext(); ++i) {                        Entry<integer> entry = (Entry)i$.next();                        param.put(entry.getValue(), args[((Integer)entry.getKey()).intValue()]);                        String genericParamName = "param" + String.valueOf(i + 1);                        if(!param.containsKey(genericParamName)) {                            param.put(genericParamName, args[((Integer)entry.getKey()).intValue()]);                        }                    }                    return param;                }            } else {                return null;            }        }/<integer>/<string>/<code>

調用DefaultSqlSession的selectList的方法

<code>public  List selectList(String statement, Object parameter, RowBounds rowBounds) {        List var5;        try {        //獲取MappedStatement對象            MappedStatement ms = this.configuration.getMappedStatement(statement);            //調用cachingExecutor執行器的方法            var5 = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);        } catch (Exception var9) {            throw ExceptionFactory.wrapException("Error querying database.  Cause: " + var9, var9);        } finally {            ErrorContext.instance().reset();        }        return var5;    }//CachingExector的query方法public  List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {    //        BoundSql boundSql = ms.getBoundSql(parameterObject);        CacheKey key = this.createCacheKey(ms, parameterObject, rowBounds, boundSql);        //調用下2代碼        return this.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);    }    //2代碼 public  List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {        Cache cache = ms.getCache();        if(cache != null) {            this.flushCacheIfRequired(ms);            if(ms.isUseCache() && resultHandler == null) {                this.ensureNoOutParams(ms, parameterObject, boundSql);                List list = (List)this.tcm.getObject(cache, key);                if(list == null) {                //這裡是調用Executor裡的query方法 如果開啟了緩存這掉CachingExecutor的 如果沒有則是調用BaseExecutor的                    list = this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);                    this.tcm.putObject(cache, key, list);                }                return list;            }        }        return this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);    }/<code>

BaseExecutor的query方法

<code>public  List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {        ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());        if(this.closed) {            throw new ExecutorException("Executor was closed.");        } else {            if(this.queryStack == 0 && ms.isFlushCacheRequired()) {                this.clearLocalCache();            }            List list;            try {                ++this.queryStack;                list = resultHandler == null?(List)this.localCache.getObject(key):null;                if(list != null) {                    this.handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);                } else {                //如果緩存中沒有就從數據庫中查詢                    list = this.queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);                }            } finally {                --this.queryStack;            }            if(this.queryStack == 0) {                Iterator i$ = this.deferredLoads.iterator();                while(i$.hasNext()) {                    BaseExecutor.DeferredLoad deferredLoad = (BaseExecutor.DeferredLoad)i$.next();                    deferredLoad.load();                }                this.deferredLoads.clear();                if(this.configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {                    this.clearLocalCache();                }            }            return list;        }    }//從數據庫中查詢private  List queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {        //放入緩存        this.localCache.putObject(key, ExecutionPlaceholder.EXECUTION_PLACEHOLDER);        List list;        try {        //此處是調用子Executor的方法,ExecutorType默認是使用的SimpleExecutor            list = this.doQuery(ms, parameter, rowBounds, resultHandler, boundSql);        } finally {            this.localCache.removeObject(key);        }        this.localCache.putObject(key, list);        if(ms.getStatementType() == StatementType.CALLABLE) {            this.localOutputParameterCache.putObject(key, parameter);        }        return list;    }/<code>

SimpleExecutor的doQuery方法

<code>public  List doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {        Statement stmt = null;        List var9;        try {            Configuration configuration = ms.getConfiguration();            //創建StateMentHandler處理器            StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);            //調用下3的方法            stmt = this.prepareStatement(handler, ms.getStatementLog());            //調用no4的方法            var9 = handler.query(stmt, resultHandler);        } finally {            this.closeStatement(stmt);        }        return var9;    }    //下3方法private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {        Connection connection = this.getConnection(statementLog);        Statement stmt = handler.prepare(connection);        //SatementHanlder 採用PreparedStatementHandler來實現此方法,而PreparedStatementHandler調用的是父接口ParameterHandler的方法        handler.parameterize(stmt);        return stmt;    }/<code>

ParameterHandler參數處理器的方法

<code>public interface ParameterHandler {    Object getParameterObject();    //此方法是用DefaultParameterHandler實現的    void setParameters(PreparedStatement var1) throws SQLException;}/<code>

DefaultParameterHandler默認參數處理器的方法

<code>public void setParameters(PreparedStatement ps) {        ErrorContext.instance().activity("setting parameters").object(this.mappedStatement.getParameterMap().getId());        List<parametermapping> parameterMappings = this.boundSql.getParameterMappings();        if(parameterMappings != null) {            for(int i = 0; i < parameterMappings.size(); ++i) {                ParameterMapping parameterMapping = (ParameterMapping)parameterMappings.get(i);                if(parameterMapping.getMode() != ParameterMode.OUT) {                    String propertyName = parameterMapping.getProperty();                    Object value;                    if(this.boundSql.hasAdditionalParameter(propertyName)) {                        value = this.boundSql.getAdditionalParameter(propertyName);                    } else if(this.parameterObject == null) {                        value = null;                    } else if(this.typeHandlerRegistry.hasTypeHandler(this.parameterObject.getClass())) {                        value = this.parameterObject;                    } else {                        MetaObject metaObject = this.configuration.newMetaObject(this.parameterObject);                        value = metaObject.getValue(propertyName);                    }                   //這裡用調用 TypeHandler類型映射處理器來映射                    TypeHandler typeHandler = parameterMapping.getTypeHandler();                    JdbcType jdbcType = parameterMapping.getJdbcType();                    if(value == null && jdbcType == null) {                        jdbcType = this.configuration.getJdbcTypeForNull();                    }                    try {                    //類型處理器設置參數映射                                               typeHandler.setParameter(ps, i + 1, value, jdbcType);                    } catch (TypeException var10) {                        throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + var10, var10);                    } catch (SQLException var11) {                        throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + var11, var11);                    }                }            }        }    }/<parametermapping>/<code>

no4的方法

<code> public  List query(Statement statement, ResultHandler resultHandler) throws SQLException {       //此處調用原生sql的處理器        PreparedStatement ps = (PreparedStatement)statement;        //發出原生sql命令        ps.execute();        //採用ResultHandler結果處理器對結果集封裝        return this.resultSetHandler.handleResultSets(ps);    }/<code> 

ResultHandler代碼

<code>public interface ResultSetHandler {    //此處調用的是DefaultResultSetHandler的方法     List handleResultSets(Statement var1) throws SQLException;    void handleOutputParameters(CallableStatement var1) throws SQLException;}/<code>

DefaultResultSetHandler的方法

<code>public List<object> handleResultSets(Statement stmt) throws SQLException {        ErrorContext.instance().activity("handling results").object(this.mappedStatement.getId());        List<object> multipleResults = new ArrayList();        int resultSetCount = 0;        ResultSetWrapper rsw = this.getFirstResultSet(stmt);        List<resultmap> resultMaps = this.mappedStatement.getResultMaps();        int resultMapCount = resultMaps.size();        this.validateResultMapsCount(rsw, resultMapCount);        while(rsw != null && resultMapCount > resultSetCount) {            ResultMap resultMap = (ResultMap)resultMaps.get(resultSetCount);            this.handleResultSet(rsw, resultMap, multipleResults, (ResultMapping)null);            rsw = this.getNextResultSet(stmt);            this.cleanUpAfterHandlingResultSet();            ++resultSetCount;        }        String[] resultSets = this.mappedStatement.getResulSets();        if(resultSets != null) {            while(rsw != null && resultSetCount < resultSets.length) {                ResultMapping parentMapping = (ResultMapping)this.nextResultMaps.get(resultSets[resultSetCount]);                if(parentMapping != null) {                    String nestedResultMapId = parentMapping.getNestedResultMapId();                    ResultMap resultMap = this.configuration.getResultMap(nestedResultMapId);                    this.handleResultSet(rsw, resultMap, (List)null, parentMapping);                }                rsw = this.getNextResultSet(stmt);                this.cleanUpAfterHandlingResultSet();                ++resultSetCount;            }        }        return this.collapseSingleResultList(multipleResults);    }//處理結果集 private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<object> multipleResults, ResultMapping parentMapping) throws SQLException {        try {            if(parentMapping != null) {                this.handleRowValues(rsw, resultMap, (ResultHandler)null, RowBounds.DEFAULT, parentMapping);            } else if(this.resultHandler == null) {                DefaultResultHandler defaultResultHandler = new DefaultResultHandler(this.objectFactory);                this.handleRowValues(rsw, resultMap, defaultResultHandler, this.rowBounds, (ResultMapping)null);                multipleResults.add(defaultResultHandler.getResultList());            } else {                this.handleRowValues(rsw, resultMap, this.resultHandler, this.rowBounds, (ResultMapping)null);            }        } finally {            this.closeResultSet(rsw.getResultSet());        }    }private void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {        if(resultMap.hasNestedResultMaps()) {            this.ensureNoRowBounds();            this.checkResultHandler();            this.handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);        } else {            this.handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);        }    }   private void handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {        DefaultResultContext<object> resultContext = new DefaultResultContext();        this.skipRows(rsw.getResultSet(), rowBounds);        Object rowValue = null;        while(this.shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {            ResultMap discriminatedResultMap = this.resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, (String)null);            CacheKey rowKey = this.createRowKey(discriminatedResultMap, rsw, (String)null);            Object partialObject = this.nestedResultObjects.get(rowKey);            if(this.mappedStatement.isResultOrdered()) {                if(partialObject == null && rowValue != null) {                    this.nestedResultObjects.clear();                    this.storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());                }        //獲取行的值                rowValue = this.getRowValue(rsw, discriminatedResultMap, rowKey, (String)null, partialObject);            } else {                rowValue = this.getRowValue(rsw, discriminatedResultMap, rowKey, (String)null, partialObject);                if(partialObject == null) {                    this.storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());                }            }        }        if(rowValue != null && this.mappedStatement.isResultOrdered() && this.shouldProcessMoreRows(resultContext, rowBounds)) {            this.storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());        }    }    String resultMapId = resultMap.getId();        Object resultObject = partialObject;        if(partialObject != null) {            MetaObject metaObject = this.configuration.newMetaObject(partialObject);            this.putAncestor(partialObject, resultMapId, columnPrefix);            this.applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, false);            this.ancestorObjects.remove(resultMapId);        } else {            ResultLoaderMap lazyLoader = new ResultLoaderMap();            resultObject = this.createResultObject(rsw, resultMap, lazyLoader, columnPrefix);            if(resultObject != null && !this.typeHandlerRegistry.hasTypeHandler(resultMap.getType())) {                MetaObject metaObject = this.configuration.newMetaObject(resultObject);                boolean foundValues = !resultMap.getConstructorResultMappings().isEmpty();                if(this.shouldApplyAutomaticMappings(resultMap, true)) {                    foundValues = this.applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;                }                foundValues = this.applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;                this.putAncestor(resultObject, resultMapId, columnPrefix);                foundValues = this.applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, true) || foundValues;                this.ancestorObjects.remove(resultMapId);                foundValues = lazyLoader.size() > 0 || foundValues;                resultObject = foundValues?resultObject:null;            }            if(combinedKey != CacheKey.NULL_CACHE_KEY) {                this.nestedResultObjects.put(combinedKey, resultObject);            }        }        return resultObject;    }private boolean shouldApplyAutomaticMappings(ResultMap resultMap, boolean isNested) {        return resultMap.getAutoMapping() != null?resultMap.getAutoMapping().booleanValue():(isNested?AutoMappingBehavior.FULL == this.configuration.getAutoMappingBehavior():AutoMappingBehavior.NONE != this.configuration.getAutoMappingBehavior());    } private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {        List<defaultresultsethandler.unmappedcolumautomapping> autoMapping = this.createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);        boolean foundValues = false;        if(autoMapping.size() > 0) {            Iterator i$ = autoMapping.iterator();            while(true) {           //這裡使用了內部類對參數和結果集進行映射               DefaultResultSetHandler.UnMappedColumAutoMapping mapping;                Object value;                do {                    if(!i$.hasNext()) {                        return foundValues;                    }                    mapping = (DefaultResultSetHandler.UnMappedColumAutoMapping)i$.next();                    value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);                } while(value == null && !this.configuration.isCallSettersOnNulls());                if(value != null || !mapping.primitive) {                    metaObject.setValue(mapping.property, value);                }                foundValues = true;            }        } else {            return foundValues;        }    } private static class UnMappedColumAutoMapping {        private final String column;        private final String property;        private final TypeHandler> typeHandler;        private final boolean primitive;    //此處才類型器對結果進行映射        public UnMappedColumAutoMapping(String column, String property, TypeHandler> typeHandler, boolean primitive) {            this.column = column;            this.property = property;            this.typeHandler = typeHandler;            this.primitive = primitive;        }    }/<defaultresultsethandler.unmappedcolumautomapping>/<object>/<object>/<resultmap>/<object>/<object>/<code>

JAVA進階架構程序員福利:我這裡還總結整理了比較全面的JAVA相關的面試資料,都已經整理成了


PDF版,這些都可以分享給大家,關注私信我:【806】,免費領取!


分享到:


相關文章: