MyBatis底层学习

1 篇文章 0 订阅
1 篇文章 0 订阅

MyBatis底层学习

mybatis-config.xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <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="org/mybatis/example/BlogMapper.xml"/>
    </mappers>
</configuration>

1.识别数据源

可以根据mybatis官方文档搭建一个mybatis,其首先是创建一个SqlSessionFactory
String resource = "org/mybatis/example/mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new 				    	   			       SqlSessionFactoryBuilder().build(inputStream);
其首先调用的是SqlSessionFactoryBuilder的build方法,将我们创建的mybatis-config。xml文件传输进去,其本质就是解析XML文件
public SqlSessionFactory build(InputStream inputStream) {
        return this.build((InputStream)inputStream, (String)null, (Properties)null);
  	}
进入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()); //此处调用XMLConfigBuilder的parse()方法,也是解析mybatis-config。xml文件的具体方法 即为build(configuration)
        } catch (Exception var14) {
            throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
        } finally {
            ErrorContext.instance().reset();

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

        }

        return var5;
    }
打开parse()方法,找到parseConfigration()方法,即找到数据源的入口
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"));
            //这里可以很明显的看到 “configuration”字段,也就是对应xml文件的<configuration>标签
            return this.configuration;
        }
    }
打开parseConfigyration(this.parse.evalNode("/configuration"))方法,可以看到里面有许多方法,仔细看就可以发现,这些就是对应解析对应名称标签的方法
private void parseConfiguration(XNode root) {
        try {
            this.propertiesElement(root.evalNode("properties"));
            Properties settings = this.settingsAsProperties(root.evalNode("settings"));
            this.loadCustomVfs(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"));
            //environments即为对应xml文件中的<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);
        }
    }
找到‘environment’,打开对应的environmentsElement(root.evalNode(“environments”))方法
private void environmentsElement(XNode context) throws Exception {
        if (context != null) {
            if (this.environment == null) {
                this.environment = context.getStringAttribute("default");
            }

            Iterator var2 = context.getChildren().iterator();//此处进行游标遍历,获取其内部的每一个子元素,即子<environment>标签,再执行while循环来获取其内部的每一个元素

            while(var2.hasNext()) {//hasnext , next方法,不在多说
                XNode child = (XNode)var2.next();
                String id = child.getStringAttribute("id");//此处取其对应的Id , 在此xml中的id=“development”的environment
                if (this.isSpecifiedEnvironment(id)) {//找到这个environment标签
                    TransactionFactory txFactory = this.transactionManagerElement(child.evalNode("transactionManager"));//对应的<transactionManager>标签 也是mybatis中事物的管理方式 此xml处使用的JDBC事物
                    DataSourceFactory dsFactory = this.dataSourceElement(child.evalNode("dataSource"));//此处对应的<dataSource>标签,也是链接我们数据库的具体标签
                    DataSource dataSource = dsFactory.getDataSource();
                    Builder environmentBuilder = (new Builder(id)).transactionFactory(txFactory).dataSource(dataSource);
                    this.configuration.setEnvironment(environmentBuilder.build());
                }
            }
        }

    }
打开dataSourceELement(child.evalNode(“dataSource”))方法
private DataSourceFactory dataSourceElement(XNode context) throws Exception {
        if (context != null) {
            String type = context.getStringAttribute("type");//找到对应的type , 此xml对应的POOLED ,(多数是) 即我们最常说的数据库连接池,结合上面部分即为JDBC数据库连接池
            Properties props = context.getChildrenAsProperties();//此处为将对应的name , value封装到一个properties中 ,也就是把(url ,driver , username , password)name 和value封装到properties中 其中properties继承的是hashtable(本人理解: 线程安全)
            DataSourceFactory factory = (DataSourceFactory)this.resolveClass(type).newInstance();
            factory.setProperties(props);
            return factory;
        } else {
            throw new BuilderException("Environment declaration requires a DataSourceFactory.");
        }
    }
至此将链接数据库的数据解析完毕,即一个Configuration放入build()方法中
public SqlSessionFactory build(Configuration config) {
        return new DefaultSqlSessionFactory(config);
    }
SqlSessionFactory创建成功;同时链接到我们配置的数据库;

2.执行语句

在parseConfiguration中找到对应的mapperElement(root.evalNode(“mappers”))方法,打开
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;
                    
                    /**
                    *这里为调用mapper.xml文件的四种方式
                    *主体分为<package> 和 <mapper>两种
                    *package下只有name
                    *mapper下由 resource url class三种
                    *其中优先级从上往下依次排列 package resource url class
                    */
                    
                    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判断 
                        *主要核心代码:
 mapperParser = new XMLMapperBuilder(inputStream, this.configuration, resource, this.configuration.getSqlFragments());
  mapperParser.parse();
                        */
                        if (resource != null && url == null && mapperClass == null) {//resouce
                            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) {//url
                            ErrorContext.instance().resource(url);
                            inputStream = Resources.getUrlAsStream(url);
                            mapperParser = new XMLMapperBuilder(inputStream, this.configuration, url, this.configuration.getSqlFragments());
                            mapperParser.parse();
                        } else { //class
                            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;
            }
        }
    }
mapperParser.parse()方法
public void parse() {
    if (!this.configuration.isResourceLoaded(this.resource)) {
        //解析对应的mapper文件的具体方法
        this.configurationElement(this.parser.evalNode("/mapper"));
        this.configuration.addLoadedResource(this.resource);
        this.bindMapperForNamespace();
    }
configurationElement(this.parser.evalNode("/mapper"))方法

仔细看里面就会发现和mapper.xml文件一一对应

private void configurationElement(XNode context) {
        try {
            String namespace = context.getStringAttribute("namespace");//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"));//parameterMap
                this.resultMapElements(context.evalNodes("/mapper/resultMap"));//resultMap
                this.sqlElement(context.evalNodes("/mapper/sql"));//sql
                this.buildStatementFromContext(context.evalNodes("select|insert|update|delete"));//这是判断所执行的sql语句是select、insert、update、delete
            } else {
                throw new BuilderException("Mapper's namespace cannot be empty");
            }
        } catch (Exception var3) {
            throw new BuilderException("Error parsing Mapper XML. Cause: " + var3, var3);
        }
    }
buildStatementFromContext(context.evalNOdes(“select|insert|update|delete”))方法
private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
        Iterator var3 = list.iterator();

        while(var3.hasNext()) {
            XNode context = (XNode)var3.next();//此处即是在mapper.xml中存在的所有sql语句 即 : 将所有sql语句存在context中
            XMLStatementBuilder statementParser = new XMLStatementBuilder(this.configuration, this.builderAssistant, context, requiredDatabaseId);//创建一个XMLStatementBuilder类,将context放入其中

            try {
                statementParser.parseStatementNode();//执行该类的这个方法
            } catch (IncompleteElementException var7) {
                this.configuration.addIncompleteStatement(statementParser);
            }
        }

    }
statementParser.parseStatementNode();数据整理,也就是解析对应mapper.xml的每一个标签,数据
public void parseStatementNode() {
        String id = this.context.getStringAttribute("id");
        String databaseId = this.context.getStringAttribute("databaseId");
        if (this.databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
            Integer fetchSize = this.context.getIntAttribute("fetchSize");
            Integer timeout = this.context.getIntAttribute("timeout");
            String parameterMap = this.context.getStringAttribute("parameterMap");
            String parameterType = this.context.getStringAttribute("parameterType");
            Class<?> parameterTypeClass = this.resolveClass(parameterType);
            String resultMap = this.context.getStringAttribute("resultMap");
            String resultType = this.context.getStringAttribute("resultType");
            String lang = this.context.getStringAttribute("lang");
            LanguageDriver langDriver = this.getLanguageDriver(lang);
            Class<?> resultTypeClass = this.resolveClass(resultType);
            String resultSetType = this.context.getStringAttribute("resultSetType");
            StatementType statementType = StatementType.valueOf(this.context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
            ResultSetType resultSetTypeEnum = this.resolveResultSetType(resultSetType);
            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());
            this.processSelectKeyNodes(id, parameterTypeClass, langDriver);
            SqlSource sqlSource = langDriver.createSqlSource(this.configuration, this.context, parameterTypeClass);
            String resultSets = this.context.getStringAttribute("resultSets");
            String keyProperty = this.context.getStringAttribute("keyProperty");
            String keyColumn = this.context.getStringAttribute("keyColumn");
            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;
            }

            this.builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, resultOrdered, (KeyGenerator)keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
        }
    }
执行builderAssistant.addMappedStatement方法将所有解析完成的数据放到这个方法里面

返回一个MappedStatment对象 , 每一个sql就对应一个这样的类

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

3.结合数据源和执行语句进行操作

SqlSession session = sqlSessionFactory.openSession();
try {
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(101);
} finally {
session.close();
}

openSession()方法

public SqlSession openSession() {
    return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, false);
}
进入openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, false);方法 即创建DefourtSqlSession
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;
    }
创建完成 DefaultSqlSession类后 , 调用其内部的selectOne方法
public <T> T selectOne(String statement) {
        return this.selectOne(statement, (Object)null);
    }
在selectOne方法中调用selectList()方法
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;
    }
}
selectList()方法中会返回一个mapperStatement
 public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
     List var5;
     try {
         MappedStatement ms = this.configuration.getMappedStatement(statement); //此处调用上部已存在的getMappedStatement方法  通过namespace+id获取对应的sql语句
         var5 = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);//此处为缓存检查 , 使用executor接口的quary方法,操作的是具体实现类cachingexecutor(缓存执行者)
     } catch (Exception var9) {
         throw ExceptionFactory.wrapException("Error querying database.  Cause: " + var9, var9);
     } finally {
         ErrorContext.instance().reset();
     }

     return var5;
 }
cachingexecutor.query(MappedStatement , Object , RowBounds,ResultHandler)方法
 public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, 		ResultHandler resultHandler) throws SQLException {
     BoundSql boundSql = ms.getBoundSql(parameterObject);//用mappedstatement调用getNoundSql,拿到对应是sql,即传入的参数等数据
     CacheKey key = this.createCacheKey(ms, parameterObject, rowBounds, boundSql);//此处为构建一个缓存(缓存机制)
     return this.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
 }
this.query方法
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) {
                    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方法
    }
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 var8 = this.deferredLoads.iterator();

                while(var8.hasNext()) {
                    BaseExecutor.DeferredLoad deferredLoad = (BaseExecutor.DeferredLoad)var8.next();
                    deferredLoad.load();
                }

                this.deferredLoads.clear();
                if (this.configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
                    this.clearLocalCache();
                }
            }

            return list;
        }
    }
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) {
            this.localOutputParameterCache.putObject(key, parameter);
        }

        return list;
    }
doQuery()方法
public <E> List<E> doQuery(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        Statement stmt = null;

        List var10;
        try {
            this.flushStatements();
            Configuration configuration = ms.getConfiguration();//获得java.sql.configuration
            StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameterObject, rowBounds, resultHandler, boundSql);//获得statementHandler
            Connection connection = this.getConnection(ms.getStatementLog());//获取java.sql.connection(即jdbc的connection)
            stmt = handler.prepare(connection, this.transaction.getTimeout());//获取statement
            handler.parameterize(stmt);
            var10 = handler.query(stmt, resultHandler);//此处执行的preparedstatementhandler中的query方法
        } finally {
            this.closeStatement(stmt);
        }

        return var10;
    }
newStatementHandler()方法
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
        StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
        StatementHandler statementHandler = (StatementHandler)this.interceptorChain.pluginAll(statementHandler);//此处为拦截器的一种方法
        return statementHandler;
    }
handler.prepare()方法
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
        ErrorContext.instance().sql(this.boundSql.getSql());
        Statement statement = null;

        try {
            statement = this.instantiateStatement(connection);
            this.setStatementTimeout(statement, transactionTimeout);
            this.setFetchSize(statement);
            return statement;
        } catch (SQLException var5) {
            this.closeStatement(statement);
            throw var5;
        } catch (Exception var6) {
            this.closeStatement(statement);
            throw new ExecutorException("Error preparing statement.  Cause: " + var6, var6);
        }
    }
handler.query()方法
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
        PreparedStatement ps = (PreparedStatement)statement;
        ps.execute();//执行sql
        return this.resultSetHandler.handleResultSets(ps);//resultset
    }
resultSetHandler.handleResultSets(ps)方法
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);//此处获取我们所需的结果集
    }
getBoundSql()方法,即为获取对应的sql语句
public BoundSql getBoundSql(Object parameterObject) {
        BoundSql boundSql = this.sqlSource.getBoundSql(parameterObject);
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();//此处拿到所需的sql及参数
        if (parameterMappings == null || parameterMappings.isEmpty()) {
            boundSql = new BoundSql(this.configuration, boundSql.getSql(), 							this.parameterMap.getParameterMappings(), parameterObject);
        }

        Iterator var4 = boundSql.getParameterMappings().iterator();

        while(var4.hasNext()) {
            ParameterMapping pm = (ParameterMapping)var4.next();
            String rmId = pm.getResultMapId();
            if (rmId != null) {
                ResultMap rm = this.configuration.getResultMap(rmId);
                if (rm != null) {
                    this.hasNestedResultMaps |= rm.hasNestedResultMaps();
                }
            }
        }

        return boundSql;
    }
createCacheKey(ms, parameterObject, rowBounds, boundSql)构建缓存 , 具体操作的是baseexecutor中的createCachekey()方法
public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
        if (this.closed) {
            throw new ExecutorException("Executor was closed.");
        } else {
            CacheKey cacheKey = new CacheKey();
            cacheKey.update(ms.getId());
            cacheKey.update(rowBounds.getOffset());
            cacheKey.update(rowBounds.getLimit());
            cacheKey.update(boundSql.getSql());
            List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
            TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry();
            Iterator var8 = parameterMappings.iterator();

            while(var8.hasNext()) {
                ParameterMapping parameterMapping = (ParameterMapping)var8.next();
                if (parameterMapping.getMode() != ParameterMode.OUT) {
                    String propertyName = parameterMapping.getProperty();
                    Object value;
                    if (boundSql.hasAdditionalParameter(propertyName)) {
                        value = boundSql.getAdditionalParameter(propertyName);
                    } else if (parameterObject == null) {
                        value = null;
                    } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
                        value = parameterObject;
                    } else {
                        MetaObject metaObject = this.configuration.newMetaObject(parameterObject);
                        value = metaObject.getValue(propertyName);
                    }

                    cacheKey.update(value);
                }
            }

            if (this.configuration.getEnvironment() != null) {
                cacheKey.update(this.configuration.getEnvironment().getId());
            }

            return cacheKey;
        }
    }

关于parseConfiguration()方法中各参数解释

属性(properties)                  系统属性占用配置
设置(settings)                    用于修改Mybatis的运行时行为
类型别名(typeAliases)              为类建立别名,一般使用更短的名称代替
类型处理器(typeHanders)            用于将预编译语句(PreparedStatement)或结果集(Result)中的JDBC类型转换为java类型
对象工场(ObjectFactor)             提供默认构造器或者执行构造参数初始化目标类型的对象
插件(plugins)                      Mybatis提供插件的方式来拦截映射
环境(environments)                 Mybatis允许配置多个环境
数据库标示供应商(databaseIdProvider) 数据库标示供应商
SQL映射文件(mappers)                Sql映射文件

mybatis中三种执行器 默认为SIMPLE

public enum ExecutorType {
    SIMPLE, //默认执行器
    REUSE,
    BATCH;

    private ExecutorType() {
    }
}

Configuration类为全局变量执行器 其中对应执行器代码为

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
        executorType = executorType == null ? this.defaultExecutorType : executorType;
        executorType = executorType == null ? ExecutorType.SIMPLE : executorType; //如果为null 则为SIMPLE
        Object executor;
        if (ExecutorType.BATCH == executorType) {
            executor = new BatchExecutor(this, transaction);
        } else if (ExecutorType.REUSE == executorType) {
            executor = new ReuseExecutor(this, transaction);
        } else {
            executor = new SimpleExecutor(this, transaction);
        }

        if (this.cacheEnabled) { //默认开启一级缓存 cacheEnabled为true(在无参构造中可见)
            executor = new CachingExecutor((Executor)executor);
        }

        Executor executor = (Executor)this.interceptorChain.pluginAll(executor);//拦截器 ,责任链设计模式
        return executor;
    }

Mybatis一级缓存默认开启

public Configuration() {
        this.safeResultHandlerEnabled = true;
        this.multipleResultSetsEnabled = true;
        this.useColumnLabel = true;
        this.cacheEnabled = true;
        this.useActualParamName = true;
        this.localCacheScope = LocalCacheScope.SESSION;
        this.jdbcTypeForNull = JdbcType.OTHER;
        this.lazyLoadTriggerMethods = new HashSet(Arrays.asList("equals", "clone", "hashCode", "toString"));
        this.defaultExecutorType = ExecutorType.SIMPLE;
        this.autoMappingBehavior = AutoMappingBehavior.PARTIAL;
        this.autoMappingUnknownColumnBehavior = AutoMappingUnknownColumnBehavior.NONE;
        this.variables = new Properties();
        this.reflectorFactory = new DefaultReflectorFactory();
        this.objectFactory = new DefaultObjectFactory();
        this.objectWrapperFactory = new DefaultObjectWrapperFactory();
        this.lazyLoadingEnabled = false;
        this.proxyFactory = new JavassistProxyFactory();
        this.mapperRegistry = new MapperRegistry(this);
        this.interceptorChain = new InterceptorChain();
        this.typeHandlerRegistry = new TypeHandlerRegistry();
        this.typeAliasRegistry = new TypeAliasRegistry();
        this.languageRegistry = new LanguageDriverRegistry();
        this.mappedStatements = new Configuration.StrictMap("Mapped Statements collection");
        this.caches = new Configuration.StrictMap("Caches collection");
        this.resultMaps = new Configuration.StrictMap("Result Maps collection");
        this.parameterMaps = new Configuration.StrictMap("Parameter Maps collection");
        this.keyGenerators = new Configuration.StrictMap("Key Generators collection");
        this.loadedResources = new HashSet();
        this.sqlFragments = new Configuration.StrictMap("XML fragments parsed from previous mappers");
        this.incompleteStatements = new LinkedList();
        this.incompleteCacheRefs = new LinkedList();
        this.incompleteResultMaps = new LinkedList();
        this.incompleteMethods = new LinkedList();
        this.cacheRefMap = new HashMap();
        this.typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
        this.typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);
        this.typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
        this.typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
        this.typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);
        this.typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);
        this.typeAliasRegistry.registerAlias("FIFO", FifoCache.class);
        this.typeAliasRegistry.registerAlias("LRU", LruCache.class);
        this.typeAliasRegistry.registerAlias("SOFT", SoftCache.class);
        this.typeAliasRegistry.registerAlias("WEAK", WeakCache.class);
        this.typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);
        this.typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);
        this.typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class);
        this.typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
        this.typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
        this.typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
        this.typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
        this.typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
        this.typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
        this.typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);
        this.typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);
        this.typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class);
        this.languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);
        this.languageRegistry.register(RawLanguageDriver.class);
    }

附流程图

总图

在这里插入图片描述

mybatis处理流程图

在这里插入图片描述

mybatis获取数据源

在这里插入图片描述

在这里插入图片描述

mybatis获取sql

在这里插入图片描述

mybatis操作数据

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值