Mybatis学习之工作流程代码详解

一、整体流程

  Mybatis是一种ORM对象关系映射架构,实现Java Object和数据库字段映射。

        

   如上图所示,Mybatis就是根据Java配置的数据源(driver、url、username、password)以及Mapper配置SQL(DQL查询、DML修改、DDL create)语句,基于JDBC底层的实现原理实现对数据库的操作。所以整体来说Mybatis工作大致分为三步:获取数据源、拿到需要执行的SQL、执行SQL语句并得到结果。我们以下面的程序入口来查看源码流程:

public class AppTest {
    @Test
    public void test() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory =new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = sqlSessionFactory.openSession();
        try {
            User user = session.selectOne("org.mybatis.example.UserMapper.selectUser", 1);
            System.out.println("user:{}"+user);
        } finally {
            session.close();
        }
    }
}

二、获取数据源

String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory =new SqlSessionFactoryBuilder().build(inputStream);

  如上代码所示,首先我们先来看看数据源的获取,查看如下代码,并进入到build方法:

public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    SqlSessionFactory var5;
    try {
        XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
        var5 = this.build(parser.parse());
    } catch (Exception var14) {
        throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
    } finally {
        ErrorContext.instance().reset();

        try {
            inputStream.close();
        } catch (IOException var13) {
            ;
        }
    }
    return var5;
}

  然后我们可以看到XMLConfigBuilder对XML进行parse:

public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
    this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}

private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
    super(new Configuration());
    this.localReflectorFactory = new DefaultReflectorFactory();
    ErrorContext.instance().resource("SQL Mapper Configuration");
    this.configuration.setVariables(props);
    this.parsed = false;
    this.environment = environment;
    this.parser = parser;
}

public Configuration parse() {
    if (this.parsed) {
        throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    } else {
        this.parsed = true;
        this.parseConfiguration(this.parser.evalNode("/configuration"));
        return this.configuration;
    }
}

private void parseConfiguration(XNode root) {
    try {
        this.propertiesElement(root.evalNode("properties"));
        Properties settings = this.settingsAsProperties(root.evalNode("settings"));
        this.loadCustomVfs(settings);
        this.loadCustomLogImpl(settings);
        this.typeAliasesElement(root.evalNode("typeAliases"));
        this.pluginElement(root.evalNode("plugins"));
        this.objectFactoryElement(root.evalNode("objectFactory"));
        this.objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
        this.reflectorFactoryElement(root.evalNode("reflectorFactory"));
        this.settingsElement(settings);
        this.environmentsElement(root.evalNode("environments"));
        this.databaseIdProviderElement(root.evalNode("databaseIdProvider"));
        this.typeHandlerElement(root.evalNode("typeHandlers"));
        this.mapperElement(root.evalNode("mappers"));
    } catch (Exception var3) {
        throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3);
    }
}

  可以看到我们进行了typeAliases以及environments元素的加载,这实际就进行了数据源的XML解析以及获取数据源信息,如下配置所示:

<configuration>
    <properties resource="config.properties"/>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="mybatis/UserMapper.xml"/>
    </mappers>
</configuration>

  接下来我们看看environmentsElement方法内部如何解析数据源:

private void environmentsElement(XNode context) throws Exception {
    if (context != null) {
        if (this.environment == null) {
            this.environment = context.getStringAttribute("default");
        }

        Iterator var2 = context.getChildren().iterator();

        while(var2.hasNext()) {
            XNode child = (XNode)var2.next();
            String id = child.getStringAttribute("id");
            if (this.isSpecifiedEnvironment(id)) {
                TransactionFactory txFactory = this.transactionManagerElement(child.evalNode("transactionManager"));
                DataSourceFactory dsFactory = this.dataSourceElement(child.evalNode("dataSource"));
                DataSource dataSource = dsFactory.getDataSource();
                Builder environmentBuilder = (new Builder(id)).transactionFactory(txFactory).dataSource(dataSource);
                this.configuration.setEnvironment(environmentBuilder.build());
            }
        }
    }
}
private DataSourceFactory dataSourceElement(XNode context) throws Exception {
    if (context != null) {
        String type = context.getStringAttribute("type");
        Properties props = context.getChildrenAsProperties();
        DataSourceFactory factory = (DataSourceFactory)this.resolveClass(type).getDeclaredConstructor().newInstance();
        factory.setProperties(props);
        return factory;
    } else {
        throw new BuilderException("Environment declaration requires a DataSourceFactory.");
    }
}

  如图所示,可以知道一共有三种DataSourceFactory实现:

        

  我们看下我们获取了配置之后,会在Configuration中通过setEnvironment存储环境信息,首先我们来看看Configuration类:

public class Configuration {
    protected Environment environment;
}

public final class Environment {
    private final String id;
    private final TransactionFactory transactionFactory;
    private final DataSource dataSource;
}

  因此可以知道数据源信息就存储在Configuration中的Environment属性中。如图所示:

          

  因此整个流程代码就是:

>org.apache.ibatis.session.SqlSessionFactoryBuilder.build(java.io.InputStream) 
 >org.apache.ibatis.builder.xml.XMLConfigBuilder
  >org.apache.ibatis.builder.xml.XMLConfigBuilder.parse
   >org.apache.ibatis.builder.xml.XMLConfigBuilder.environmentsElement
     >org.apache.ibatis.datasource.DataSourceFactory.getDataSource
       >org.apache.ibatis.session.Configuration.setEnvironment###### set数据源

  流程图如下:

    

三、SQL获取

  在我们成功获取了所有数据源信息后,接下来就是获取SQL执行语句,在上面的配置加载过程中,有这么一句会进行Mapper的加载:

private void parseConfiguration(XNode root) {
    try {
        this.propertiesElement(root.evalNode("properties"));
        Properties settings = this.settingsAsProperties(root.evalNode("settings"));
        this.loadCustomVfs(settings);
        this.loadCustomLogImpl(settings);
        this.typeAliasesElement(root.evalNode("typeAliases"));
        this.pluginElement(root.evalNode("plugins"));
        this.objectFactoryElement(root.evalNode("objectFactory"));
        this.objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
        this.reflectorFactoryElement(root.evalNode("reflectorFactory"));
        this.settingsElement(settings);
        this.environmentsElement(root.evalNode("environments"));
        this.databaseIdProviderElement(root.evalNode("databaseIdProvider"));
        this.typeHandlerElement(root.evalNode("typeHandlers"));
        this.mapperElement(root.evalNode("mappers"));
    } catch (Exception var3) {
        throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3);
    }
}

  我们进入到方法内部进行查看,如下代码所示:

private void mapperElement(XNode parent) throws Exception {
    if (parent != null) {
        Iterator var2 = parent.getChildren().iterator();

        while(true) {
            while(var2.hasNext()) {
                XNode child = (XNode)var2.next();
                String resource;
                if ("package".equals(child.getName())) {
                    resource = child.getStringAttribute("name");
                    this.configuration.addMappers(resource);
                } else {
                    resource = child.getStringAttribute("resource");
                    String url = child.getStringAttribute("url");
                    String mapperClass = child.getStringAttribute("class");
                    XMLMapperBuilder mapperParser;
                    InputStream inputStream;
                    if (resource != null && url == null && mapperClass == null) {
                        ErrorContext.instance().resource(resource);
                        inputStream = Resources.getResourceAsStream(resource);
                        mapperParser = new XMLMapperBuilder(inputStream, this.configuration, resource, this.configuration.getSqlFragments());
                        mapperParser.parse();
                    } else if (resource == null && url != null && mapperClass == null) {
                        ErrorContext.instance().resource(url);
                        inputStream = Resources.getUrlAsStream(url);
                        mapperParser = new XMLMapperBuilder(inputStream, this.configuration, url, this.configuration.getSqlFragments());
                        mapperParser.parse();
                    } else {
                        if (resource != null || url != null || mapperClass == null) {
                            throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
                        }

                        Class<?> mapperInterface = Resources.classForName(mapperClass);
                        this.configuration.addMapper(mapperInterface);
                    }
                }
            }
            return;
        }
    }
}

  可以看到mapper的解析有四种方式(resource、url、class、package),其实对应配置方式就是:

    <mappers>
        <mapper resource="mybatis/UserMapper.xml"/>
        <mapper url="file:///var/mappers/AuthorMapper.xml"/>
        <mapper class="com.generator.mapper.UserMapper"></mapper>
        <package name="com.generator.mapper"></package>
    </mappers>

  我们以XML为例在方法内部查看时如何进行解析的,进入到XMLMapperBuilder中的parse流程:

public void parse() {
    if (!this.configuration.isResourceLoaded(this.resource)) {
        this.configurationElement(this.parser.evalNode("/mapper"));
        this.configuration.addLoadedResource(this.resource);
        this.bindMapperForNamespace();
    }

    this.parsePendingResultMaps();
    this.parsePendingCacheRefs();
    this.parsePendingStatements();
}private void configurationElement(XNode context) {
    try {
        String namespace = context.getStringAttribute("namespace");
        if (namespace != null && !namespace.equals("")) {
            this.builderAssistant.setCurrentNamespace(namespace);
            this.cacheRefElement(context.evalNode("cache-ref"));
            this.cacheElement(context.evalNode("cache"));
            this.parameterMapElement(context.evalNodes("/mapper/parameterMap"));
            this.resultMapElements(context.evalNodes("/mapper/resultMap"));
            this.sqlElement(context.evalNodes("/mapper/sql"));
            this.buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
        } else {
            throw new BuilderException("Mapper's namespace cannot be empty");
        }
    } catch (Exception var3) {
        throw new BuilderException("Error parsing Mapper XML. The XML location is '" + this.resource + "'. Cause: " + var3, var3);
    }
}

private void buildStatementFromContext(List<XNode> list) {
    if (this.configuration.getDatabaseId() != null) {
        this.buildStatementFromContext(list, this.configuration.getDatabaseId());
    }

    this.buildStatementFromContext(list, (String)null);
}

private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
    Iterator var3 = list.iterator();

    while(var3.hasNext()) {
        XNode context = (XNode)var3.next();
        XMLStatementBuilder statementParser = new XMLStatementBuilder(this.configuration, this.builderAssistant, context, requiredDatabaseId);

        try {
            statementParser.parseStatementNode();
        } catch (IncompleteElementException var7) {
            this.configuration.addIncompleteStatement(statementParser);
        }
    }
}

  然后我们看到了statementParse的parseStatementNode方法,进入到方法,可以看到:

public void parseStatementNode() {
    String id = this.context.getStringAttribute("id");
    String databaseId = this.context.getStringAttribute("databaseId");
    if (this.databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
        String nodeName = this.context.getNode().getNodeName();
        SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
        boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
        boolean flushCache = this.context.getBooleanAttribute("flushCache", !isSelect);
        boolean useCache = this.context.getBooleanAttribute("useCache", isSelect);
        boolean resultOrdered = this.context.getBooleanAttribute("resultOrdered", false);
        XMLIncludeTransformer includeParser = new XMLIncludeTransformer(this.configuration, this.builderAssistant);
        includeParser.applyIncludes(this.context.getNode());
        String parameterType = this.context.getStringAttribute("parameterType");
        Class<?> parameterTypeClass = this.resolveClass(parameterType);
        String lang = this.context.getStringAttribute("lang");
        LanguageDriver langDriver = this.getLanguageDriver(lang);
        this.processSelectKeyNodes(id, parameterTypeClass, langDriver);
        String keyStatementId = id + "!selectKey";
        keyStatementId = this.builderAssistant.applyCurrentNamespace(keyStatementId, true);
        Object keyGenerator;
        if (this.configuration.hasKeyGenerator(keyStatementId)) {
            keyGenerator = this.configuration.getKeyGenerator(keyStatementId);
        } else {
            keyGenerator = this.context.getBooleanAttribute("useGeneratedKeys", this.configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType)) ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
        }

        SqlSource sqlSource = langDriver.createSqlSource(this.configuration, this.context, parameterTypeClass);
        StatementType statementType = StatementType.valueOf(this.context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
        Integer fetchSize = this.context.getIntAttribute("fetchSize");
        Integer timeout = this.context.getIntAttribute("timeout");
        String parameterMap = this.context.getStringAttribute("parameterMap");
        String resultType = this.context.getStringAttribute("resultType");
        Class<?> resultTypeClass = this.resolveClass(resultType);
        String resultMap = this.context.getStringAttribute("resultMap");
        String resultSetType = this.context.getStringAttribute("resultSetType");
        ResultSetType resultSetTypeEnum = this.resolveResultSetType(resultSetType);
        if (resultSetTypeEnum == null) {
            resultSetTypeEnum = this.configuration.getDefaultResultSetType();
        }

        String keyProperty = this.context.getStringAttribute("keyProperty");
        String keyColumn = this.context.getStringAttribute("keyColumn");
        String resultSets = this.context.getStringAttribute("resultSets");
        this.builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, resultOrdered, (KeyGenerator)keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
    }
}

public MappedStatement addMappedStatement(String id, SqlSource sqlSource, StatementType statementType, SqlCommandType sqlCommandType, Integer fetchSize, Integer timeout, String parameterMap, Class<?> parameterType, String resultMap, Class<?> resultType, ResultSetType resultSetType, boolean flushCache, boolean useCache, boolean resultOrdered, KeyGenerator keyGenerator, String keyProperty, String keyColumn, String databaseId, LanguageDriver lang, String resultSets) {
    if (this.unresolvedCacheRef) {
        throw new IncompleteElementException("Cache-ref not yet resolved");
    } else {
        id = this.applyCurrentNamespace(id, false);
        boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
        org.apache.ibatis.mapping.MappedStatement.Builder statementBuilder = (new org.apache.ibatis.mapping.MappedStatement.Builder(this.configuration, id, sqlSource, sqlCommandType)).resource(this.resource).fetchSize(fetchSize).timeout(timeout).statementType(statementType).keyGenerator(keyGenerator).keyProperty(keyProperty).keyColumn(keyColumn).databaseId(databaseId).lang(lang).resultOrdered(resultOrdered).resultSets(resultSets).resultMaps(this.getStatementResultMaps(resultMap, resultType, id)).resultSetType(resultSetType).flushCacheRequired((Boolean)this.valueOrDefault(flushCache, !isSelect)).useCache((Boolean)this.valueOrDefault(useCache, isSelect)).cache(this.currentCache);
        ParameterMap statementParameterMap = this.getStatementParameterMap(parameterMap, parameterType, id);
        if (statementParameterMap != null) {
            statementBuilder.parameterMap(statementParameterMap);
        }

        MappedStatement statement = statementBuilder.build();
        this.configuration.addMappedStatement(statement);
        return statement;
    }
}

  因此我们发现SQL语句也被加载到Configuration中了,如图所示:

          

  因此我们可以知道流程是这样子的:

>org.apache.ibatis.session.SqlSessionFactoryBuilder.build(java.io.InputStream) 
 >org.apache.ibatis.builder.xml.XMLConfigBuilder
   >org.apache.ibatis.builder.xml.XMLConfigBuilder.mapperElement
     >org.apache.ibatis.builder.xml.XMLMapperBuilder
       >org.apache.ibatis.builder.xml.XMLMapperBuilder.parse
         >org.apache.ibatis.builder.xml.XMLMapperBuilder.buildStatementFromContext(java.util.List<org.apache.ibatis.parsing.XNode>)
           >org.apache.ibatis.builder.xml.XMLStatementBuilder.parseStatementNode
            >org.apache.ibatis.session.Configuration.addMappedStatement ######set 这个sql

  流程图如下所示:

     

四、SQL执行

  接下来我们看看怎么用存储的数据源信息以及SQL语句进行执行获取结果:

SqlSession session = sqlSessionFactory.openSession();
try {
    User user = session.selectOne("org.mybatis.example.UserMapper.selectUser", 1);
    System.out.println("user:{}"+user);
} finally {
    session.close();
}

  我们先看看openSession,我们以SqlSessionFactory的默认实现DefaultSqlSessionFactory为例,代码如下:

public class DefaultSqlSessionFactory implements SqlSessionFactory {
    private final Configuration configuration;

    public SqlSession openSession() {
        return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, false);
    }

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

  可以看见我们初始化了一个SQLSession,接下来我们看selectOne如何调用SQL:

public <T> T selectOne(String statement) {
    return this.selectOne(statement, (Object)null);
}

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

public <E> List<E> selectList(String statement, Object parameter) {
    return this.selectList(statement, parameter, RowBounds.DEFAULT);
}

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,然后调用executor进行执行,我们以SimpleExecutor为例,代码如下:

public class SimpleExecutor extends BaseExecutor {
    public SimpleExecutor(Configuration configuration, Transaction transaction) {
        super(configuration, transaction);
    }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;
    }
}

  我们接下来随便查看一个PreparedStatement的实现类PreparedStatementWrapper,代码如下:

public class PreparedStatementHandler extends BaseStatementHandler {

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

  继续看结果处理:

public class DefaultResultSetHandler implements ResultSetHandler {

    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.getResultSets();
        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);
    }
}

  接下来看ResultSetWrapper:

    public ResultSetWrapper(ResultSet rs, Configuration configuration) throws SQLException {
        this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
        this.resultSet = rs;
        ResultSetMetaData metaData = rs.getMetaData();
        int columnCount = metaData.getColumnCount();

        for(int i = 1; i <= columnCount; ++i) {
            this.columnNames.add(configuration.isUseColumnLabel() ? metaData.getColumnLabel(i) : metaData.getColumnName(i));
            this.jdbcTypes.add(JdbcType.forCode(metaData.getColumnType(i)));
            this.classNames.add(metaData.getColumnClassName(i));
        }

    }

  因此可以看出为什么Mybatis是一个ORM模型架构,因为实现了数据库列和Java对象属性的一一映射,如下图所示:

  

  综上所述,SQL执行代码流程如下:

org.apache.ibatis.session.defaults.DefaultSqlSessionFactory.openSession()
 >org.apache.ibatis.session.defaults.DefaultSqlSessionFactory.openSessionFromDataSource
  >org.apache.ibatis.session.Configuration.newExecutor(org.apache.ibatis.transaction.Transaction, org.apache.ibatis.session.ExecutorType)
    >org.apache.ibatis.session.defaults.DefaultSqlSession.DefaultSqlSession(org.apache.ibatis.session.Configuration, org.apache.ibatis.executor.Executor, boolean)
      >org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(java.lang.String, java.lang.Object)
        >org.apache.ibatis.executor.SimpleExecutor.doQuery
           >org.apache.ibatis.executor.statement.PreparedStatementHandler.query
             >org.apache.ibatis.executor.resultset.ResultSetWrapper.ResultSetWrapper

  因此SQL执行的时序图如下图所示:

            

  而且根据以上代码,可以看出Mybatis是基于JDBC实现的,也是使用Connection、Statement、PrepareStatement、ResultSet进行SQL运行。

五、Mybatis执行流程总结

  根据代码走读,可以看出Mybatis执行流程如下所示:

  • Mybatis根据配置项将数据源DataSource和Mapper加载到Configuration的environment和statement中;
  • SqlSessionFactoryBuilder根据Configuration配置的数据源信息build一个SQLSessionFactory;
  • SqlSessionFactory工厂通过OpenSession创建一个SqlSession;
  • SqlSession调用自身的Executor根据COnfiguration中的statement配置创建一个StatementHandler进行SQL执行;
  • StatementHandler执行的结果通过ResultSetWrapper实现数据库列和Java类属性列一一映射,得到Java结果。 

       

猜你喜欢

转载自www.cnblogs.com/jing99/p/12918603.html
今日推荐