• MyBatis源码分析


    MyBatis源码分析

    流程分析:

    1.MyBatis如何获得数据源对象

    1.1.进入

    //获得session工厂对象
    
    //1.2.
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
    

    1.2.buid()

    public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
        SqlSessionFactory var5;
        try {
            
            //environment, properties皆为数据源环境
            XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
            
            //调用解析方法
            //1.3.
            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;
    }
    

    1.3.parse():解析内容

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

    1.4.parseConfiguration

    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);
            
            //数据源环境
            //1.5.
            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);
        }
    }
    

    1.5.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"));
                    
                    //1.6.
                    //获得dataSource
                    DataSourceFactory dsFactory = this.dataSourceElement(child.evalNode("dataSource"));
                    
                    DataSource dataSource = dsFactory.getDataSource();
                    Builder environmentBuilder = (new Builder(id)).transactionFactory(txFactory).dataSource(dataSource);
                    
                     //1.8.
                    this.configuration.setEnvironment(environmentBuilder.build());
                }
            }
        }
    
    }
    

    1.6.dataSourceElement

    private DataSourceFactory dataSourceElement(XNode context) throws Exception {
        if (context != null) {
            
            //获得数据库连接池类型
            String type = context.getStringAttribute("type");
            Properties props = context.getChildrenAsProperties();
            
            //1.7
            DataSourceFactory factory = (DataSourceFactory)this.resolveClass(type).newInstance();
            factory.setProperties(props);
            return factory;
        } else {
            throw new BuilderException("Environment declaration requires a DataSourceFactory.");
        }
    }
    

    1.7.resolveClass

    protected Class<?> resolveClass(String alias) {
        if (alias == null) {
            return null;
        } else {
            try {
                return this.resolveAlias(alias);
            } catch (Exception var3) {
                throw new BuilderException("Error resolving class. Cause: " + var3, var3);
            }
        }
    }
    

    1.8.setEnvironment

    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }
    
    public final class Environment {
        private final String id;
        private final TransactionFactory transactionFactory;
        private final DataSource dataSource;
    

    sqlMapConfig.xml:

    <configuration>
    
        <!--通过properties标签加载外部properties文件-->
        <properties resource="jdbc.properties"></properties>
    
        <!--自定义别名-->
        <typeAliases>
            <typeAlias type="com.itheima.domain.User" alias="user"></typeAlias>
        </typeAliases>
    
        <!--数据源环境-->
        <environments default="developement">
            <environment id="developement">
                <transactionManager type="JDBC"></transactionManager>
                <dataSource type="POOLED">
                    <property name="driver" value="${jdbc.driver}"/>
                    <property name="url" value="${jdbc.url}"/>
                    <property name="username" value="${jdbc.username}"/>
                    <property name="password" value="${jdbc.password}"/>
                </dataSource>
            </environment>
        </environments>
        
    
        <!--加载映射文件-->
        <mappers>
            <mapper resource="com/itheima/mapper/UserMapper.xml"></mapper>
        <mappers>
    
    
    </configuration>
    

    可看见,xml中的配置与源码中的数据如id,

    transactionFactory,dataSource是一一对应的,就像实体类与数据库中的内容一样。

    Configuration

    public class Configuration {
        protected Environment environment;
        protected boolean safeRowBoundsEnabled;
        protected boolean safeResultHandlerEnabled;
        protected boolean mapUnderscoreToCamelCase;
        protected boolean aggressiveLazyLoading;
        protected boolean multipleResultSetsEnabled;
        protected boolean useGeneratedKeys;
        protected boolean useColumnLabel;
        protected boolean cacheEnabled;
        protected boolean callSettersOnNulls;
        protected boolean useActualParamName;
        protected boolean returnInstanceForEmptyRow;
        protected String logPrefix;
        protected Class<? extends Log> logImpl;
        protected Class<? extends VFS> vfsImpl;
        protected LocalCacheScope localCacheScope;
        protected JdbcType jdbcTypeForNull;
        protected Set<String> lazyLoadTriggerMethods;
        protected Integer defaultStatementTimeout;
        protected Integer defaultFetchSize;
        protected ExecutorType defaultExecutorType;
        protected AutoMappingBehavior autoMappingBehavior;
        protected AutoMappingUnknownColumnBehavior autoMappingUnknownColumnBehavior;
        protected Properties variables;
        protected ReflectorFactory reflectorFactory;
        protected ObjectFactory objectFactory;
        protected ObjectWrapperFactory objectWrapperFactory;
        protected boolean lazyLoadingEnabled;
        protected ProxyFactory proxyFactory;
        protected String databaseId;
        protected Class<?> configurationFactory;
        protected final MapperRegistry mapperRegistry;
        protected final InterceptorChain interceptorChain;
        protected final TypeHandlerRegistry typeHandlerRegistry;
        protected final TypeAliasRegistry typeAliasRegistry;
        protected final LanguageDriverRegistry languageRegistry;
        protected final Map<String, MappedStatement> mappedStatements;
        protected final Map<String, Cache> caches;
        protected final Map<String, ResultMap> resultMaps;
        protected final Map<String, ParameterMap> parameterMaps;
        protected final Map<String, KeyGenerator> keyGenerators;
        protected final Set<String> loadedResources;
        protected final Map<String, XNode> sqlFragments;
        protected final Collection<XMLStatementBuilder> incompleteStatements;
        protected final Collection<CacheRefResolver> incompleteCacheRefs;
        protected final Collection<ResultMapResolver> incompleteResultMaps;
        protected final Collection<MethodResolver> incompleteMethods;
        protected final Map<String, String> cacheRefMap;
    

    2.MyBatis如何拿到sql语句?

    2.1.XMLConfigBuilder.class:parseConfiguration

    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"));
            this.databaseIdProviderElement(root.evalNode("databaseIdProvider"));
            this.typeHandlerElement(root.evalNode("typeHandlers"));
            
            //2.2
            this.mapperElement(root.evalNode("mappers"));
        } catch (Exception var3) {
            throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3);
        }
    }
    

    2.2.XMLConfigBuilder.class:mapperElement

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

    2.3.XMLConfigBuilder.class:parse()

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

    2.4.XMLConfigBuilder.class:configurationElement

    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"));
                
                //2.5.
                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);
        }
    }
    

    sqlMapperXml:

    <mapper namespace="userMapper">
    
        <!--删除操作-->
        <delete id="delete" parameterType="int">
            delete from user where id=#{abc}
        </delete>
    
        <!--修改操作-->
        <update id="update" parameterType="com.itheima.domain.User">
            update user set username=#{username},password=#{password} where id=#{id}
        </update>
    
      
    
    </mapper>
    

    2.5.XMLConfigBuilder.class:buildStatementFromContext

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

    2.6.XMLConfigBuilder.class:buildStatementFromContext

    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 {
                
                //2.7.
                statementParser.parseStatementNode();
            } catch (IncompleteElementException var7) {
                this.configuration.addIncompleteStatement(statementParser);
            }
        }
    
    }
    

    2.6.XMLConfigBuilder.class:parseStatementNode()

    sqlMapper中的各种属性

    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;
            }
    
            //2.7.
            ths.builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, resultOrdered, (KeyGenerator)keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
        }
    }
    

    2.7.XMLConfigBuilder.class:addMappedStatement

    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();
            //2.8.
            this.configuration.addMappedStatement(statement);
            return statement;
        }
    }
    

    2.8.Configuration:addMappedStatement

    public void addMappedStatement(MappedStatement ms) {
        this.mappedStatements.put(ms.getId(), ms);
    }
    

    3.MyBatis如何操作数据库的?

    3.1.获得session回话对象

    //获得session回话对象
    SqlSession sqlSession = sqlSessionFactory.openSession();//openSession() method just do some prepared jobs
    

    3.2.DeFaultSqlSessionFactory.class: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);
            
            //3.3. Executor
            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;
    }
    

    How many kide of Executor?

    answer:three

    public enum ExecutorType {
        SIMPLE,
        REUSE,
        BATCH;//a group of people or things
    
        private ExecutorType() {
        }
    }
    

    3.3.execute operation

    //执行操作  参数:namespace+id
    User user = sqlSession.selectOne("userMapper.findById", 1);
    

    3.4.DefaultSqlSession:selectList()

    public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
        List var5;
        try {
            MappedStatement ms = this.configuration.getMappedStatement(statement);
            
            //3.5.enter query method
            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;
    }
    

    3.5.CachingExecutor:query()

    public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
       
        //binding sql
        BoundSql boundSql = ms.getBoundSql(parameterObject);
        CacheKey key = this.createCacheKey(ms, parameterObject, rowBounds, boundSql);
        return this.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
    }
    

    3.6.BaseExecutor.java:

    query about cache

    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;
                
                // to judge weather has the cache or not 
                list = resultHandler == null ? (List)this.localCache.getObject(key) : null;
                //the cache is't null
                if (list != null) {
                    this.handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
                } else {
                    // the cache is null,to query from the database
                    //3.7
                    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;
        }
    }
    

    3.7.BaseExecutor.java:queryFromDatabase

    private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
        //First Level Cache: put the key in cache
        this.localCache.putObject(key, ExecutionPlaceholder.EXECUTION_PLACEHOLDER);
    
        List list;
        try {
            
            //3.8.
            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;
    }
    

    3.8.SimpleExecutor.java: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();
            
            //3.9.
            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;
    }
    

    3.9.RoutingStatementHandler:

    public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
        
        //3.10.
        return this.delegate.query(statement, resultHandler);
    }
    

    3.10.PreparedStatementHandler:query

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

    3.11.DefaultResultSetHandler.java: getFirstResultSet

    private ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException {
        ResultSet rs = stmt.getResultSet();
    
        while(rs == null) {
            if (stmt.getMoreResults()) {
                rs = stmt.getResultSet();
            } else if (stmt.getUpdateCount() == -1) {
                break;
            }
        }
    
        //3.12.
        return rs != null ? new ResultSetWrapper(rs, this.configuration) : null;
    }
    

    3.12.ResultSetWrapper.java: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) {
            
            //convert data type between java and sql.As the picture shown below
            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));
        }
    
    }
    

  • 相关阅读:
    010_STM32CubeMXADC
    009_STM32CubeMXPWM
    008_STM32CubeMX定时器中断
    007_STM32CubeMX外部中断
    006_STM32CubeMX按键输入
    005_STM32CubeMX串口
    004_STM32CubeMX官方例程
    003_STM32CubeMX点灯
    002_STM32CubeMX配置基础工程
    006_word发表博客到博客园中
  • 原文地址:https://www.cnblogs.com/aaaazzzz/p/13201670.html
Copyright © 2020-2023  润新知