编程知识 cdmana.com

[mybatis] - get sqlsession source code analysis

At the end of the last blog, I asked a question , Let's solve the first article : sqlSession How did it come about ? as well as xml How is it loaded into configuration Of ?
 Insert picture description here

1、 First ,SqlSessionFactoryBuilder Read out mybatis Configuration file for , then build One DefaultSqlSessionFactory. Source code is as follows :

  public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
    try {
      // adopt XMLConfigBuilder Parse configuration file , The parsed configuration related information is encapsulated as a Configuration object 
      XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
      // Created here DefaultSessionFactory object 
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        reader.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }

  public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
  }

2、 analysis mybatis The configuration file , First, judge whether the configuration file has been parsed , Parsing is allowed only if it has not been parsed . Which calls parser.evalNode(“/configuration”) Returns the root node's org.apache.ibatis.parsing.XNode Express ,XNode It mainly structured the key node attributes and placeholder variables , As shown below :

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

 Insert picture description here And then call parseConfiguration according to mybatis The main configuration of the

private void parseConfiguration(XNode root) {
    try {
      //issue #117 read properties first
      propertiesElement(root.evalNode("properties"));
      Properties settings = settingsAsProperties(root.evalNode("settings"));
      loadCustomVfs(settings);
      typeAliasesElement(root.evalNode("typeAliases"));
      pluginElement(root.evalNode("plugins"));
      objectFactoryElement(root.evalNode("objectFactory"));
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      reflectorFactoryElement(root.evalNode("reflectorFactory"));
      settingsElement(settings);
      // read it after objectFactory and objectWrapperFactory issue #631
      environmentsElement(root.evalNode("environments"));
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      typeHandlerElement(root.evalNode("typeHandlers"));
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }

Finally back to configuration

3、 And then call xmlMapperBuilder.parse() take mapper.xml File loading to configuration in
 Insert picture description here The corresponding code in the figure above :

if (!isEmpty(this.mapperLocations)) {
      for (Resource mapperLocation : this.mapperLocations) {
        if (mapperLocation == null) {
          continue;
        }

        try {
          XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),
              configuration, mapperLocation.toString(), configuration.getSqlFragments());
          xmlMapperBuilder.parse();
        } catch (Exception e) {
          throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);
        } finally {
          ErrorContext.instance().reset();
        }

        if (LOGGER.isDebugEnabled()) {
          LOGGER.debug("Parsed mapper file: '" + mapperLocation + "'");
        }
      }
    } else {
      if (LOGGER.isDebugEnabled()) {
        LOGGER.debug("Property 'mapperLocations' was not specified or no matching resources found");
      }
    }

 Insert picture description here The corresponding code in the figure above :

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

    parsePendingResultMaps();
    parsePendingCacheRefs();
    parsePendingStatements();
  }

mapper.xml Parsing is similar to parsing configuration files

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

4、 When we get SqlSessionFactory and configuration after , I can create sqlSessionFactory
 Insert picture description here The corresponding code in the figure above :

public class SqlSessionFactoryBuilder {
	public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
  }
}

5、 When we go back to sqlSessionFactory, You can go through sqlSessionFactory obtain sqlSession

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      //  adopt configuration obtain Environment,Environment Contains the data source of the transaction 
      final Environment environment = configuration.getEnvironment();
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      // Said before the , On the surface , We use it sqlSession In execution sql sentence ,  Actually , Actually by excutor perform , excutor Is for Statement Encapsulation 
      final Executor executor = configuration.newExecutor(tx, execType);
      //  The point is here , Create a DefaultSqlSession
      return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
      closeTransaction(tx); // may have fetched a connection so lets call close()
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

So the first problem is solved ,sqlSession It is a connecting link between the preceding and the following , Now we know sqlSession How did it come about , Next we understand mapper.java Interface and mapper.xml How the documents are linked ? as well as mepper Interface does not implement class , How to operate the database ?

版权声明
本文为[Wooden pine cat]所创,转载请带上原文链接,感谢

Scroll to Top