当前位置:首页 > 未命名 > 正文内容

MyBatis源码解读--从入口类SqlSessionFactoryBuilder出发

淙嶙7年前 (2018-05-31)未命名1240
先摘抄一段MyBatis官方文档代码:
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
1.SqlSessionFactoryBuilder就是官方指定的入口了,这个类只做了一件事,就是生成SqlSessionFactory,只有一个被多次重载的方法public SqlSessionFactory build(...){}, 此处做两个处理:a.将字符或字节流的文件转化成Configuration,b.将Configuration作为参数给DefaultSqlSessionFactory,返回SqlSessoinFactory(DefaultSqlSessionFactory)对象.
 
    public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
        SqlSessionFactory var5;
        try {
            XMLConfigBuilder e = new XMLConfigBuilder(inputStream, environment, properties);
            var5 = this.build((Configuration)e.parse());//配置信息,处理sql的mapper等都在这里处理,
        } catch (Exception var14) {
            throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
        } finally {
            ErrorContext.instance().reset();

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

        }

        return var5;
    }
 
public Configuration parse() {//SqlSessionFactoryBuilder的方法build中调用这个方法
        if(this.parsed) {
            throw new BuilderException("Each MapperConfigParser 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.typeAliasesElement(root.evalNode("typeAliases"));
            this.pluginElement(root.evalNode("plugins"));
            this.objectFactoryElement(root.evalNode("objectFactory"));
            this.objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
            this.propertiesElement(root.evalNode("properties"));
            this.settingsElement(root.evalNode("settings"));
            this.environmentsElement(root.evalNode("environments"));
            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 i$ = parent.getChildren().iterator();

            while(i$.hasNext()) {
                XNode child = (XNode)i$.next();
                String resource = child.getStringAttribute("resource");
                String url = child.getStringAttribute("url");
                InputStream inputStream;
                XMLMapperBuilder mapperParser;
                if(resource != null && url == null) {
                    ErrorContext.instance().resource(resource);
                    inputStream = Resources.getResourceAsStream(resource);
                    mapperParser = new XMLMapperBuilder(inputStream, this.configuration, resource, this.configuration.getSqlFragments());
                    mapperParser.parse();
                } else {
                    if(url == null || resource != null) {
                        throw new BuilderException("A mapper element may only specify a url or resource, but not both.");
                    }

                    ErrorContext.instance().resource(url);
                    inputStream = Resources.getUrlAsStream(url);
                    mapperParser = new XMLMapperBuilder(inputStream, this.configuration, url, this.configuration.getSqlFragments());
                    mapperParser.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.parsePendingChacheRefs();
        this.parsePendingStatements();
    }
private void configurationElement(XNode context) {
        try {
            String e = context.getStringAttribute("namespace");
            this.builderAssistant.setCurrentNamespace(e);
            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"));
        } catch (Exception var3) {
            throw new RuntimeException("Error parsing Mapper XML. Cause: " + var3, var3);
        }
    }
 private void buildStatementFromContext(List list) {
        Iterator i$ = list.iterator();

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

            try {
                statementParser.parseStatementNode();
            } catch (IncompleteStatementException var6) {
                this.configuration.addIncompleteStatement(statementParser);
            }
        }

    }
 public void parseStatementNode() {
        String id = this.context.getStringAttribute("id");
        Integer fetchSize = this.context.getIntAttribute("fetchSize", (Integer)null);
        Integer timeout = this.context.getIntAttribute("timeout", (Integer)null);
        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");
        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);
        List contents = this.parseDynamicTags(this.context);
        MixedSqlNode rootSqlNode = new MixedSqlNode(contents);
        DynamicSqlSource sqlSource = new DynamicSqlSource(this.configuration, rootSqlNode);
        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", Boolean.valueOf(!isSelect)).booleanValue();
        boolean useCache = this.context.getBooleanAttribute("useCache", Boolean.valueOf(isSelect)).booleanValue();
        String keyProperty = this.context.getStringAttribute("keyProperty");
        String keyStatementId = id + "!selectKey";
        keyStatementId = this.builderAssistant.applyCurrentNamespace(keyStatementId);
        Object keyGenerator;
        if(this.configuration.hasKeyGenerator(keyStatementId)) {
            keyGenerator = this.configuration.getKeyGenerator(keyStatementId);
        } else {
            keyGenerator = this.context.getBooleanAttribute("useGeneratedKeys", Boolean.valueOf(this.configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType))).booleanValue()?new Jdbc3KeyGenerator(this.context.getStringAttribute("keyColumn", (String)null)):new NoKeyGenerator();
        }

        this.builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, (KeyGenerator)keyGenerator, keyProperty);
    }
  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, KeyGenerator keyGenerator, String keyProperty) {
        id = this.applyCurrentNamespace(id);
        boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
        org.apache.ibatis.mapping.MappedStatement.Builder statementBuilder = new org.apache.ibatis.mapping.MappedStatement.Builder(this.configuration, id, sqlSource, sqlCommandType);
        statementBuilder.resource(this.resource);
        statementBuilder.fetchSize(fetchSize);
        statementBuilder.statementType(statementType);
        statementBuilder.keyGenerator(keyGenerator);
        statementBuilder.keyProperty(keyProperty);
        this.setStatementTimeout(timeout, statementBuilder);
        this.setStatementParameterMap(parameterMap, parameterType, statementBuilder);
        this.setStatementResultMap(resultMap, resultType, resultSetType, statementBuilder);
        this.setStatementCache(isSelect, flushCache, useCache, this.currentCache, statementBuilder);
        MappedStatement statement = statementBuilder.build();
        this.configuration.addMappedStatement(statement);
        return statement;
    }
2.XMLConfigBuilder:通过XPathParse将文件转化成Document,然后XMLConfigBuilder再将Document转化成Configuration。 3.获取SqlSession:SqlSession session = sqlSessionFactory.openSession();根据Configuration生成Executor,作为DefaultSqlSession构造参数,返回DefaultSqlSession。
  
 public SqlSession openSession() {
        return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, false);
 }
 private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
        Connection connection = null;
        DefaultSqlSession var10;
        try {
            Environment e = this.configuration.getEnvironment();
            DataSource dataSource = this.getDataSourceFromEnvironment(e);
            TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(e);
            connection = dataSource.getConnection();
            if(level != null) {
                connection.setTransactionIsolation(level.getLevel());
            }
            connection = this.wrapConnection(connection);
            Transaction tx = transactionFactory.newTransaction(connection, autoCommit);
            Executor executor = this.configuration.newExecutor(tx, execType);//生成executor
            var10 = new DefaultSqlSession(this.configuration, executor, autoCommit);
        } catch (Exception var14) {
            this.closeConnection(connection);
            throw ExceptionFactory.wrapException("Error opening session.  Cause: " + var14, var14);
        } finally {
            ErrorContext.instance().reset();
        }

        return var10;
    }
 public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
        executorType = executorType == null?this.defaultExecutorType:executorType;
        executorType = executorType == null?ExecutorType.SIMPLE:executorType;
        Object executor;
        if(ExecutorType.BATCH == executorType) {
            // BatchExecutor的设计主要是用于做批量更新操作的。其底层会调用Statement的executeBatch()方法实现批量操作
            executor = new BatchExecutor(this, transaction);
        } else if(ExecutorType.REUSE == executorType) {
/*是可以重用的Executor。它重用的是Statement对象,它会在内部利用一个Map把创建的Statement都缓存起来,
 *每次在执行一条SQL语句时,它都会去判断之前是否存在基于该SQL缓存的Statement对象,存在而且之前缓存的Statement对象对应的Connection还没有关闭的时候就继续用之前的Statement对象,
 *否则将创建一个新的Statement对象,并将其缓存起来。因为每一个新的SqlSession都有一个新的Executor对象,所以我们缓存在ReuseExecutor上的Statement的作用域是同一个SqlSession。*/
            executor = new ReuseExecutor(this, transaction);
        } else {
           //SimpleExecutor是Mybatis执行Mapper语句时默认使用的Executor。它提供最基本的Mapper语句执行功能,没有过多的封装的
            executor = new SimpleExecutor(this, transaction);
        }

        if(this.cacheEnabled) {
            executor = new CachingExecutor((Executor)executor);
        }

        Executor executor1 = (Executor)this.interceptorChain.pluginAll(executor);
        return executor1;
    }
4.查询
SqlSession session = sqlSessionFactory.openSession();
try {
  Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);
} finally {
  session.close();
}
selectOne 调用selectList:
public <T> T selectOne(String statement, Object parameter) {
  List<T> list = this.<T>selectList(statement, parameter);
  //...略过非主要代码
  return list.get(0);
}
在selectList最终调用:
public List selectList(String statement, Object parameter, RowBounds rowBounds) {
    List var5;
    try {
        MappedStatement e = this.configuration.getMappedStatement(statement);
        var5 = this.executor.query(e, 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;
}

相关文章

构建短字符串

构建短字符串

描述 给定任意一个较短的子串,和另一个较长的字符串,判断短的字符串是否能够由长字符串中的字符构建出来,且长串中的每个字符只能用一次。 输入 一行数据包括一个较短的字符串和一个较长的字...

大数相乘

大数相乘

数学公式:AB X CD = AC (BC+AD) BD package com.dl.study.m1.d1; import java.util.Scanner; /** * Create...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。