美文网首页源代码
Mybatis 源码分析(二)之 Mybatis 操作数据库的流

Mybatis 源码分析(二)之 Mybatis 操作数据库的流

作者: 挂机的啊洋zzZ | 来源:发表于2019-01-31 23:50 被阅读32次
    2.jpg

    Mybatis 源码分析(二)之 Mybatis 操作数据库的流程

    Mybatis系列:
    Mybatis 基础介绍与逆向工程的构建 :https://www.jianshu.com/p/1c18db4d7a38
    Mybatis 源码分析(一)之 Mybatis 的Executor的初始化:https://www.jianshu.com/p/c7425c841337
    Mybatis 源码分析(二)之 Mybatis 操作数据库的流程 :https://www.jianshu.com/p/11d354ec3612
    Mybatis 源码分析(三)之 Mybatis 的一级缓存和二级缓存 :https://www.jianshu.com/p/5515640d14fe


    承接之前的 Mybatis 源码分析(一)之 Mybatis 的Executor的初始化 继续进行之后的源码分析。
    在之前的分析中,我们知道初始化Executor的流程。

    SqlSessionFactoryBuilder->parse->Configuation->build->SqlSessionFactory->openSession->SqlSession->query->Executor
    

    接下来则是mybatis操作数据库的流程


    执行查询

    org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object, org.apache.ibatis.session.RowBounds)
        
    public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
        List var5;
        try {
            MappedStatement ms = this.configuration.getMappedStatement(statement);
            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;
    }
    

    其中

    MappedStatement ms = this.configuration.getMappedStatement(statement);
    

    getMappedStatement是个map进行get,statement是我们传入的selectByPrimaryKey等参数,如下中的id。

    <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
        select 
        <include refid="Base_Column_List" />
        from food
        where id = #{id,jdbcType=INTEGER}
    </select>
    

    进行进入query

    org.apache.ibatis.executor.BaseExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)
    
    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;
        }
    }
    

    其中

    list = resultHandler == null ? (List)this.localCache.getObject(key) : null;
    

    传入的参数key,就是我们拼出来的cache key : cache key: id + sql + limit + offset

    例如:

    -2061571805:4913609797:com.demo.mybatis.mapper.UserMapper.selectByPrimaryKey:0:2147483647:select 
     
    id, name, age
    
    from user
    where id = ?:1:development
    

    假如第一次查询没有缓存,则查询数据库

    list = this.queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
    

    继续进去

    org.apache.ibatis.executor.BaseExecutor#queryFromDatabase
    
    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 {
             //查询数据
            list = this.doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
        } finally {
            //删除占位的
            this.localCache.removeObject(key);
        }
    
        //将查询出来的结果存入一级缓存
        this.localCache.putObject(key, list);
        if (ms.getStatementType() == StatementType.CALLABLE) {
            //如果是存储过程把参数存入localOutputParameterCache
            this.localOutputParameterCache.putObject(key, parameter);
        }
    
        return list;
    }
    

    进行数据查询

    org.apache.ibatis.executor.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 handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
            stmt = this.prepareStatement(handler, ms.getStatementLog());
            var9 = handler.query(stmt, resultHandler);
        } finally {
            this.closeStatement(stmt);
        }
    
        return var9;
    }
    

    进入query

    org.apache.ibatis.executor.statement.PreparedStatementHandler#query
    
    public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
        PreparedStatement ps = (PreparedStatement)statement;
        ps.execute();
        return this.resultSetHandler.handleResultSets(ps);
    }
    

    其中

     ps.execute();
    

    底层仍然是我们熟悉的JDBC

    java.sql.PreparedStatement#execute
    

    然后进入handleResultSets对我们的结果信息进封装,最后返回给我们的,就是我们定义的pojo

    org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleResultSets
    
    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 List<Object> collapseSingleResultList(List<Object> multipleResults) {
        return multipleResults.size() == 1 ? (List)multipleResults.get(0) : multipleResults;
    }
    

    调用链

    org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(java.lang.String, java.lang.Object)
     >org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(java.lang.String, java.lang.Object)
       >org.apache.ibatis.session.Configuration.getMappedStatement(java.lang.String)
        >org.apache.ibatis.executor.CachingExecutor.query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler)
         >org.apache.ibatis.executor.CachingExecutor.createCacheKey 创建缓存的key
          >org.apache.ibatis.executor.CachingExecutor.query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)
             >org.apache.ibatis.executor.BaseExecutor.queryFromDatabase
               >org.apache.ibatis.executor.BaseExecutor.doQuery
                 >org.apache.ibatis.executor.statement.PreparedStatementHandler.query
                   >org.apache.ibatis.executor.resultset.ResultSetHandler.handleResultSets
                    >org.apache.ibatis.executor.resultset.DefaultResultSetHandler
    

    上面是操作数据库的流程,其中真正干活的是handler,mybatis底层操作数据库的仍然是我们熟悉的JDBC。

    其中获取mapper的过程

    org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSessionFromDataSource
    
    private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
        Transaction tx = null;
    
        DefaultSqlSession var8;
        try {
            Environment environment = this.configuration.getEnvironment();
            TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
            tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
            Executor executor = this.configuration.newExecutor(tx, execType);
            var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
        } catch (Exception var12) {
            this.closeTransaction(tx);
            throw ExceptionFactory.wrapException("Error opening session.  Cause: " + var12, var12);
        } finally {
            ErrorContext.instance().reset();
        }
    
        return var8;
    }
    

    其中

    var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
    

    然后

    org.apache.ibatis.session.defaults.DefaultSqlSession#getMapper
    
    public <T> T getMapper(Class<T> type) {
            return this.configuration.getMapper(type, this);
        }
        
        
    org.apache.ibatis.session.Configuration#getMapper
    
    public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        return this.mapperRegistry.getMapper(type, sqlSession);
    }
    
    org.apache.ibatis.binding.MapperRegistry#getMapper
    
    public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
        if (mapperProxyFactory == null) {
            throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
        } else {
            try {
                return mapperProxyFactory.newInstance(sqlSession);
            } catch (Exception var5) {
                throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
            }
        }
    }
    

    调用链

    org.apache.ibatis.session.defaults.DefaultSqlSession.getMapper
       >org.apache.ibatis.session.Configuration.getMapper
        >org.apache.ibatis.binding.MapperRegistry.getMapper
          >org.apache.ibatis.binding.MapperProxyFactory.newInstance(org.apache.ibatis.session.SqlSession)
            >org.apache.ibatis.binding.MapperMethod.execute
    

    其中获取sql的过程

    org.apache.ibatis.binding.MapperMethod#execute
    
    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()) {
            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;
        }
    }
    

    然后

    org.apache.ibatis.session.defaults.DefaultSqlSession#selectOne(java.lang.String, java.lang.Object)
    
    public <T> T selectOne(String statement, Object parameter) {
        List<T> list = this.selectList(statement, parameter);
        if (list.size() == 1) {
            return list.get(0);
        } else if (list.size() > 1) {
            throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
        } else {
            return null;
        }
    }
    
    org.apache.ibatis.executor.BaseExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler)
    
    public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
        BoundSql boundSql = ms.getBoundSql(parameter);
        CacheKey key = this.createCacheKey(ms, parameter, rowBounds, boundSql);
        return this.query(ms, parameter, rowBounds, resultHandler, key, boundSql);
    }
    

    最后

    org.apache.ibatis.mapping.MappedStatement#getBoundSql
    
    public BoundSql getBoundSql(Object parameterObject) {
        BoundSql boundSql = this.sqlSource.getBoundSql(parameterObject);
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        if (parameterMappings == null || parameterMappings.isEmpty()) {
            boundSql = new BoundSql(this.configuration, boundSql.getSql(), this.parameterMap.getParameterMappings(), parameterObject);
        }
    
        Iterator i$ = boundSql.getParameterMappings().iterator();
    
        while(i$.hasNext()) {
            ParameterMapping pm = (ParameterMapping)i$.next();
            String rmId = pm.getResultMapId();
            if (rmId != null) {
                ResultMap rm = this.configuration.getResultMap(rmId);
                if (rm != null) {
                    this.hasNestedResultMaps |= rm.hasNestedResultMaps();
                }
            }
        }
    
        return boundSql;
    }
    

    调用链

    org.apache.ibatis.binding.MapperMethod.execute
    >org.apache.ibatis.session.SqlSession.selectOne(java.lang.String, java.lang.Object)
      >org.apache.ibatis.executor.BaseExecutor.query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler)
        >org.apache.ibatis.mapping.MappedStatement.getBoundSql
    
    总结

    整个流程如下:

    SqlSessionFactoryBuilder->parse->Configuation->build->SqlSessionFactory
    ->openSession->SqlSession->query->Executor->newStatementHandler->
    StatementHandler->handlerResultSets->ResultSetHandler
    

    感觉还有些没有写完整,不定期进行补充:)
    如有问题,欢迎留言:)

    相关文章

      网友评论

        本文标题:Mybatis 源码分析(二)之 Mybatis 操作数据库的流

        本文链接:https://www.haomeiwen.com/subject/dzhrsqtx.html