1. 程式人生 > >Mybatis之工作原理

Mybatis之工作原理

1.Mybatis的架構

1.1 Mybatis的框架分層

這裡寫圖片描述

1.2 MyBatis的實現原理

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


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

其中StatementHandler用通過ParameterHandler與ResultHandler分別進行引數預編譯 與結果處理。而ParameterHandler與ResultHandler都使用TypeHandler進行對映。如下圖:
這裡寫圖片描述

2.Mybatis工作過程

通過讀mybatis的原始碼進行分析mybatis的執行操作的整個過程,我們通過debug除錯就可以知道Mybatis每一步做了什麼事,我先把debug每一步結果 截圖,然後在分析這個流程。
第一步:讀取配置檔案,形成InputStream

2.1 建立SqlSessionFacotry的過程

這裡寫圖片描述
從debug除錯看出 返回的 sqlSessionFactory 是DefaultSesssionFactory型別的,但是configuration此時已經被初始化了。檢視原始碼後畫如下建立DefaultSessionFactory的時序圖:
這裡寫圖片描述

2.2 建立SqlSession的過程

這裡寫圖片描述
從debug除錯 看出SqlSessinoFactory.openSession() 返回的sqlSession是 DefaultSession型別的,此SqlSession裡包含一個Configuration的物件,和一個Executor物件。檢視原始碼後畫如下建立DefaultSession的時序圖:

這裡寫圖片描述

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


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, MapperMethod> 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;
    }

經過上面的呼叫後進入MapperMethod裡面執行

//判斷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 <E> 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, Object> param = new MapperMethod.ParamMap();
                    int i = 0;

                    for(Iterator i$ = this.params.entrySet().iterator(); i$.hasNext(); ++i) {
                        Entry<Integer, String> 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;
            }
        }

呼叫DefaultSqlSession的selectList的方法

   public <E> List<E> 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 <E> List<E> 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 <E> List<E> 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<E> 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);
    }

BaseExecutor的query方法

public <E> List<E> 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 <E> List<E> 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;
    }

SimpleExecutor的doQuery方法

public <E> List<E> 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;
    }

ParameterHandler引數處理器的方法

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

DefaultParameterHandler預設引數處理器的方法

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);
                    }
                }
            }
        }

    }

no4的方法

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

ResultHandler程式碼

public interface ResultSetHandler {
    //此處呼叫的是DefaultResultSetHandler的方法
    <E> List<E> handleResultSets(Statement var1) throws SQLException;

    void handleOutputParameters(CallableStatement var1) throws SQLException;
}

DefaultResultSetHandler的方法

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;
        }
    }