博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
简单读!Mybatis源码(一)一条select的一生
阅读量:7239 次
发布时间:2019-06-29

本文共 64629 字,大约阅读时间需要 215 分钟。

      工具除了会用,还应该多做点。我觉得使用一个软件工具(开源类),一般会经历几个步骤:

1. 通过wiki了解大致作用,然后开始码代码;

2. 系统性地学习其特性,找出可能需要的点,用上去;

3. 通过阅读其源码,清楚其来龙去脉;

4. 有能力你就去超越别人;

      mybatis作为orm框架给我们带来了很多方便,其定制功能也让我们惊喜!还是来看看别人怎么做到的吧!

  1. 下载git仓库, https://github.com/mybatis/mybatis-3

  2. 打开IDE, 找到 test 包

  3. 进入 org.apache.ibatis.autoconstructor.AutoConstructorTest, 有一个完整的sql 样例

public class AutoConstructorTest {  private static SqlSessionFactory sqlSessionFactory;  @BeforeClass  public static void setUp() throws Exception {    // create a SqlSessionFactory    try (Reader reader = Resources.getResourceAsReader("org/apache/ibatis/autoconstructor/mybatis-config.xml")) {      sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);    }    // populate in-memory database    BaseDataTest.runScript(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(),        "org/apache/ibatis/autoconstructor/CreateDB.sql");  }  @Test  public void fullyPopulatedSubject() {    try (SqlSession sqlSession = sqlSessionFactory.openSession()) {      final AutoConstructorMapper mapper = sqlSession.getMapper(AutoConstructorMapper.class);      final Object subject = mapper.getSubject(1);      assertNotNull(subject);    }  }  @Test(expected = PersistenceException.class)  public void primitiveSubjects() {    try (SqlSession sqlSession = sqlSessionFactory.openSession()) {      final AutoConstructorMapper mapper = sqlSession.getMapper(AutoConstructorMapper.class);      mapper.getSubjects();    }  }  @Test  public void annotatedSubject() {    try (SqlSession sqlSession = sqlSessionFactory.openSession()) {      final AutoConstructorMapper mapper = sqlSession.getMapper(AutoConstructorMapper.class);      verifySubjects(mapper.getAnnotatedSubjects());    }  }  @Test(expected = PersistenceException.class)  public void badSubject() {    try (SqlSession sqlSession = sqlSessionFactory.openSession()) {      final AutoConstructorMapper mapper = sqlSession.getMapper(AutoConstructorMapper.class);      mapper.getBadSubjects();    }  }  @Test  public void extensiveSubject() {    try (SqlSession sqlSession = sqlSessionFactory.openSession()) {      final AutoConstructorMapper mapper = sqlSession.getMapper(AutoConstructorMapper.class);      verifySubjects(mapper.getExtensiveSubject());    }  }  private void verifySubjects(final List
subjects) { assertNotNull(subjects); Assertions.assertThat(subjects.size()).isEqualTo(3); }}

 

 目标方法:fullyPopulatedSubject(),最终进行一条 select 查询:

SELECT * FROM subject WHERE id = #{id}

首先执行的肯定 setup()方法了,setup()做了三件事:

    1. 加载mybatis-config文件读取到reader中;

    2. 将配置文件传递工厂builder中创建会话工厂;

    3. 执行hsqldb内存数据库的初始化工作;(非本文重点)

接下来,咱们从源码的角度,主要看会话工厂的创建过程!

创建 sqlSessionFactory

try (Reader reader = Resources.getResourceAsReader("org/apache/ibatis/autoconstructor/mybatis-config.xml")) {      sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);    }    // SqlSessionFactoryBuilder.build(reader) -> XMLConfigBuilder.parse()// org.apache.ibatis.session.SqlSessionFactoryBuilder  public SqlSessionFactory build(Reader reader) {    return build(reader, null, null);  }  // 建立factory  public SqlSessionFactory build(Reader reader, String environment, Properties properties) {    try {      XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);      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.      }    }  }

 

 标签解析:

/** * Offline entity resolver for the MyBatis DTDs *  * @author Clinton Begin * @author Eduardo Macarron */public class XMLMapperEntityResolver implements EntityResolver {  private static final String IBATIS_CONFIG_SYSTEM = "ibatis-3-config.dtd";  private static final String IBATIS_MAPPER_SYSTEM = "ibatis-3-mapper.dtd";  private static final String MYBATIS_CONFIG_SYSTEM = "mybatis-3-config.dtd";  private static final String MYBATIS_MAPPER_SYSTEM = "mybatis-3-mapper.dtd";  private static final String MYBATIS_CONFIG_DTD = "org/apache/ibatis/builder/xml/mybatis-3-config.dtd";  private static final String MYBATIS_MAPPER_DTD = "org/apache/ibatis/builder/xml/mybatis-3-mapper.dtd";  /**   * Converts a public DTD into a local one   *    * @param publicId The public id that is what comes after "PUBLIC"   * @param systemId The system id that is what comes after the public id.   * @return The InputSource for the DTD   *    * @throws org.xml.sax.SAXException If anything goes wrong   */  @Override  public InputSource resolveEntity(String publicId, String systemId) throws SAXException {    try {      if (systemId != null) {        String lowerCaseSystemId = systemId.toLowerCase(Locale.ENGLISH);        if (lowerCaseSystemId.contains(MYBATIS_CONFIG_SYSTEM) || lowerCaseSystemId.contains(IBATIS_CONFIG_SYSTEM)) {          return getInputSource(MYBATIS_CONFIG_DTD, publicId, systemId);        } else if (lowerCaseSystemId.contains(MYBATIS_MAPPER_SYSTEM) || lowerCaseSystemId.contains(IBATIS_MAPPER_SYSTEM)) {          return getInputSource(MYBATIS_MAPPER_DTD, publicId, systemId);        }      }      return null;    } catch (Exception e) {      throw new SAXException(e.toString());    }  }  private InputSource getInputSource(String path, String publicId, String systemId) {    InputSource source = null;    if (path != null) {      try {        InputStream in = Resources.getResourceAsStream(path);        source = new InputSource(in);        source.setPublicId(publicId);        source.setSystemId(systemId);              } catch (IOException e) {        // ignore, null is ok      }    }    return source;  }}

 

 parser

// org.apache.ibatis.parsing.XPathParser.XPathParser(), 设备一些必要参数  public XPathParser(Reader reader, boolean validation, Properties variables, EntityResolver entityResolver) {    commonConstructor(validation, variables, entityResolver);    this.document = createDocument(new InputSource(reader));  }  private Document createDocument(InputSource inputSource) {    // important: this must only be called AFTER common constructor    try {      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();      factory.setValidating(validation);      factory.setNamespaceAware(false);      factory.setIgnoringComments(true);      factory.setIgnoringElementContentWhitespace(false);      factory.setCoalescing(false);      factory.setExpandEntityReferences(true);      DocumentBuilder builder = factory.newDocumentBuilder();      builder.setEntityResolver(entityResolver);      builder.setErrorHandler(new ErrorHandler() {        @Override        public void error(SAXParseException exception) throws SAXException {          throw exception;        }        @Override        public void fatalError(SAXParseException exception) throws SAXException {          throw exception;        }        @Override        public void warning(SAXParseException exception) throws SAXException {        }      });      return builder.parse(inputSource);    } catch (Exception e) {      throw new BuilderException("Error creating document instance.  Cause: " + e, e);    }  }

// 在返回fatory的时候调用 return build(parser.parse()); 将 config.xml 的配置全部解析到 configuration 实例中

// 在返回fatory的时候调用 return build(parser.parse());  将 config.xml 的配置全部解析到 configuration 实例中// org.apache.ibatis.builder.xml.XMLConfigBuilder.parse()  public Configuration parse() {    if (parsed) {      throw new BuilderException("Each XMLConfigBuilder can only be used once.");    }    parsed = true;    // 根元素为 /configuration, 依次向下解析    parseConfiguration(parser.evalNode("/configuration"));    return configuration;  }    // org.apache.ibatis.parsing.XPathParser.evalNode() 映射 xml 属性到 bean   public XNode evalNode(Object root, String expression) {    Node node = (Node) evaluate(expression, root, XPathConstants.NODE);    if (node == null) {      return null;    }    return new XNode(this, node, variables);  }  private Object evaluate(String expression, Object root, QName returnType) {    try {      return xpath.evaluate(expression, root, returnType);    } catch (Exception e) {      throw new BuilderException("Error evaluating XPath.  Cause: " + e, e);    }  }

具体解析项如下,从这里也一目了然,配置项支持什么:

// 解析各配置参数到实例中  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"));      // 重要节点,解析 mapper      mapperElement(root.evalNode("mappers"));    } catch (Exception e) {      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);    }  }

下面依次来看一下都怎么解析各配置项的吧~

properties 解析

// propertiesElement(root.evalNode("properties"));  url, resource 解析  private void propertiesElement(XNode context) throws Exception {    if (context != null) {      Properties defaults = context.getChildrenAsProperties();      String resource = context.getStringAttribute("resource");      String url = context.getStringAttribute("url");      if (resource != null && url != null) {        throw new BuilderException("The properties element cannot specify both a URL and a resource based property file reference.  Please specify one or the other.");      }      if (resource != null) {        defaults.putAll(Resources.getResourceAsProperties(resource));      } else if (url != null) {        defaults.putAll(Resources.getUrlAsProperties(url));      }      Properties vars = configuration.getVariables();      if (vars != null) {        defaults.putAll(vars);      }      // 解析完成后,放到 parser 和 configuration 实例中      parser.setVariables(defaults);      configuration.setVariables(defaults);    }  }

settings 配置项解析,返回内容待处理

// Properties settings = settingsAsProperties(root.evalNode("settings"));  private Properties settingsAsProperties(XNode context) {    if (context == null) {      return new Properties();    }    Properties props = context.getChildrenAsProperties();    // Check that all settings are known to the configuration class    MetaClass metaConfig = MetaClass.forClass(Configuration.class, localReflectorFactory);    for (Object key : props.keySet()) {      if (!metaConfig.hasSetter(String.valueOf(key))) {        throw new BuilderException("The setting " + key + " is not known.  Make sure you spelled it correctly (case sensitive).");      }    }    return props;  }    // loadCustomVfs(settings);  这个...  private void loadCustomVfs(Properties props) throws ClassNotFoundException {    String value = props.getProperty("vfsImpl");    if (value != null) {      String[] clazzes = value.split(",");      for (String clazz : clazzes) {        if (!clazz.isEmpty()) {          @SuppressWarnings("unchecked")          Class
vfsImpl = (Class
)Resources.classForName(clazz); configuration.setVfsImpl(vfsImpl); } } } }

 

typeAliases 别名设置解析,主要做类型检查,及别名的注册工作

// typeAliasesElement(root.evalNode("typeAliases"));  private void typeAliasesElement(XNode parent) {    if (parent != null) {      for (XNode child : parent.getChildren()) {        if ("package".equals(child.getName())) {          // 针对package配置,需注册一系列别名,以 simpleName 代替          String typeAliasPackage = child.getStringAttribute("name");          configuration.getTypeAliasRegistry().registerAliases(typeAliasPackage);        } else {          String alias = child.getStringAttribute("alias");          String type = child.getStringAttribute("type");          try {            Class
clazz = Resources.classForName(type); if (alias == null) { typeAliasRegistry.registerAlias(clazz); } else { typeAliasRegistry.registerAlias(alias, clazz); } } catch (ClassNotFoundException e) { throw new BuilderException("Error registering typeAlias for '" + alias + "'. Cause: " + e, e); } } } } } // org.apache.ibatis.type.TypeAliasRegistry.registerAlias(), 具体数据结构为 map 封装 public void registerAlias(Class
type) { String alias = type.getSimpleName(); Alias aliasAnnotation = type.getAnnotation(Alias.class); if (aliasAnnotation != null) { alias = aliasAnnotation.value(); } registerAlias(alias, type); } public void registerAlias(String alias, Class
value) { if (alias == null) { throw new TypeException("The parameter alias cannot be null"); } // issue #748 String key = alias.toLowerCase(Locale.ENGLISH); if (TYPE_ALIASES.containsKey(key) && TYPE_ALIASES.get(key) != null && !TYPE_ALIASES.get(key).equals(value)) { throw new TypeException("The alias '" + alias + "' is already mapped to the value '" + TYPE_ALIASES.get(key).getName() + "'."); } TYPE_ALIASES.put(key, value); }

 

 

plugins 配置项解析,将属性注入的plugin, 添加 plugin 到 configuration

// pluginElement(root.evalNode("plugins"));  private void pluginElement(XNode parent) throws Exception {    if (parent != null) {      for (XNode child : parent.getChildren()) {        String interceptor = child.getStringAttribute("interceptor");        Properties properties = child.getChildrenAsProperties();        // 先创建一个plugin实例,备用        Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance();        // 配置属性的注入,回调        interceptorInstance.setProperties(properties);        // 添加到 configuration        configuration.addInterceptor(interceptorInstance);      }    }  }public class InterceptorChain {  private final List
interceptors = new ArrayList<>(); public Object pluginAll(Object target) { for (Interceptor interceptor : interceptors) { target = interceptor.plugin(target); } return target; } public void addInterceptor(Interceptor interceptor) { interceptors.add(interceptor); } public List
getInterceptors() { return Collections.unmodifiableList(interceptors); }}

 

objectFactory 配置项解析,与plugin原理相似,做替换自定义作用

// objectFactoryElement(root.evalNode("objectFactory"));  private void objectFactoryElement(XNode context) throws Exception {    if (context != null) {      String type = context.getStringAttribute("type");      Properties properties = context.getChildrenAsProperties();      ObjectFactory factory = (ObjectFactory) resolveClass(type).newInstance();      factory.setProperties(properties);      configuration.setObjectFactory(factory);    }  }    // objectWrapperFactoryElement(root.evalNode("objectWrapperFactory")); 没什么特别  private void objectWrapperFactoryElement(XNode context) throws Exception {    if (context != null) {      String type = context.getStringAttribute("type");      ObjectWrapperFactory factory = (ObjectWrapperFactory) resolveClass(type).newInstance();      configuration.setObjectWrapperFactory(factory);    }  }

 

// reflectorFactoryElement(root.evalNode("reflectorFactory"));  private void reflectorFactoryElement(XNode context) throws Exception {    if (context != null) {       String type = context.getStringAttribute("type");       ReflectorFactory factory = (ReflectorFactory) resolveClass(type).newInstance();       configuration.setReflectorFactory(factory);    }  }

 

settings 选项解析,设置各种开关, 如缓存

// settingsElement(settings);  设置各种开关, 如缓存  private void settingsElement(Properties props) throws Exception {    configuration.setAutoMappingBehavior(AutoMappingBehavior.valueOf(props.getProperty("autoMappingBehavior", "PARTIAL")));    configuration.setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior.valueOf(props.getProperty("autoMappingUnknownColumnBehavior", "NONE")));    configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true));    configuration.setProxyFactory((ProxyFactory) createInstance(props.getProperty("proxyFactory")));    configuration.setLazyLoadingEnabled(booleanValueOf(props.getProperty("lazyLoadingEnabled"), false));    configuration.setAggressiveLazyLoading(booleanValueOf(props.getProperty("aggressiveLazyLoading"), false));    configuration.setMultipleResultSetsEnabled(booleanValueOf(props.getProperty("multipleResultSetsEnabled"), true));    configuration.setUseColumnLabel(booleanValueOf(props.getProperty("useColumnLabel"), true));    configuration.setUseGeneratedKeys(booleanValueOf(props.getProperty("useGeneratedKeys"), false));    configuration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE")));    configuration.setDefaultStatementTimeout(integerValueOf(props.getProperty("defaultStatementTimeout"), null));    configuration.setDefaultFetchSize(integerValueOf(props.getProperty("defaultFetchSize"), null));    configuration.setMapUnderscoreToCamelCase(booleanValueOf(props.getProperty("mapUnderscoreToCamelCase"), false));    configuration.setSafeRowBoundsEnabled(booleanValueOf(props.getProperty("safeRowBoundsEnabled"), false));    configuration.setLocalCacheScope(LocalCacheScope.valueOf(props.getProperty("localCacheScope", "SESSION")));    configuration.setJdbcTypeForNull(JdbcType.valueOf(props.getProperty("jdbcTypeForNull", "OTHER")));    configuration.setLazyLoadTriggerMethods(stringSetValueOf(props.getProperty("lazyLoadTriggerMethods"), "equals,clone,hashCode,toString"));    configuration.setSafeResultHandlerEnabled(booleanValueOf(props.getProperty("safeResultHandlerEnabled"), true));    configuration.setDefaultScriptingLanguage(resolveClass(props.getProperty("defaultScriptingLanguage")));    @SuppressWarnings("unchecked")    Class
typeHandler = (Class
)resolveClass(props.getProperty("defaultEnumTypeHandler")); configuration.setDefaultEnumTypeHandler(typeHandler); configuration.setCallSettersOnNulls(booleanValueOf(props.getProperty("callSettersOnNulls"), false)); configuration.setUseActualParamName(booleanValueOf(props.getProperty("useActualParamName"), true)); configuration.setReturnInstanceForEmptyRow(booleanValueOf(props.getProperty("returnInstanceForEmptyRow"), false)); configuration.setLogPrefix(props.getProperty("logPrefix")); @SuppressWarnings("unchecked") Class
logImpl = (Class
)resolveClass(props.getProperty("logImpl")); configuration.setLogImpl(logImpl); configuration.setConfigurationFactory(resolveClass(props.getProperty("configurationFactory"))); }

 environments 环境配置设置,根据指定环境,获取相应配置,加载数据源配置

// environmentsElement(root.evalNode("environments")); 环境配置  private void environmentsElement(XNode context) throws Exception {    if (context != null) {      if (environment == null) {        // 默认为 development        environment = context.getStringAttribute("default");      }      for (XNode child : context.getChildren()) {        String id = child.getStringAttribute("id");        // 查找当前环境配置,指定加载        if (isSpecifiedEnvironment(id)) {          // 事务管理、数据源          TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));          DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));          DataSource dataSource = dsFactory.getDataSource();          Environment.Builder environmentBuilder = new Environment.Builder(id)              .transactionFactory(txFactory)              .dataSource(dataSource);          configuration.setEnvironment(environmentBuilder.build());        }      }    }  }    // 环境配置包含, id, 事务管理, 数据源    public Environment build() {      return new Environment(this.id, this.transactionFactory, this.dataSource);    }

 databaseIdProvider 解析,对多数据源,包含多 机器,或多类型数据库 mysql,sqlserver

// databaseIdProviderElement(root.evalNode("databaseIdProvider"));   private void databaseIdProviderElement(XNode context) throws Exception {    DatabaseIdProvider databaseIdProvider = null;    if (context != null) {      String type = context.getStringAttribute("type");      // awful patch to keep backward compatibility      if ("VENDOR".equals(type)) {          type = "DB_VENDOR";      }      Properties properties = context.getChildrenAsProperties();      databaseIdProvider = (DatabaseIdProvider) resolveClass(type).newInstance();      databaseIdProvider.setProperties(properties);    }    Environment environment = configuration.getEnvironment();    if (environment != null && databaseIdProvider != null) {      String databaseId = databaseIdProvider.getDatabaseId(environment.getDataSource());      configuration.setDatabaseId(databaseId);    }  }

 

自定义 typeHandler

// typeHandlerElement(root.evalNode("typeHandlers")); 自定义 typeHandler  private void typeHandlerElement(XNode parent) throws Exception {    if (parent != null) {      for (XNode child : parent.getChildren()) {        if ("package".equals(child.getName())) {          String typeHandlerPackage = child.getStringAttribute("name");          typeHandlerRegistry.register(typeHandlerPackage);        } else {          String javaTypeName = child.getStringAttribute("javaType");          String jdbcTypeName = child.getStringAttribute("jdbcType");          String handlerTypeName = child.getStringAttribute("handler");          Class
javaTypeClass = resolveClass(javaTypeName); JdbcType jdbcType = resolveJdbcType(jdbcTypeName); Class
typeHandlerClass = resolveClass(handlerTypeName); if (javaTypeClass != null) { if (jdbcType == null) { typeHandlerRegistry.register(javaTypeClass, typeHandlerClass); } else { typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass); } } else { typeHandlerRegistry.register(typeHandlerClass); } } } } } // org.apache.ibatis.type.TypeHandlerRegistry.register(), 以map保存映射 private void register(Type javaType, JdbcType jdbcType, TypeHandler
handler) { if (javaType != null) { Map
> map = TYPE_HANDLER_MAP.get(javaType); if (map == null || map == NULL_TYPE_HANDLER_MAP) { map = new HashMap<>(); TYPE_HANDLER_MAP.put(javaType, map); } map.put(jdbcType, handler); } ALL_TYPE_HANDLERS_MAP.put(handler.getClass(), handler); }

 mapper 解析,crud

// mapperElement(root.evalNode("mappers"));  private void mapperElement(XNode parent) throws Exception {    if (parent != null) {      for (XNode child : parent.getChildren()) {        if ("package".equals(child.getName())) {          String mapperPackage = child.getStringAttribute("name");          configuration.addMappers(mapperPackage);        } else {          String resource = child.getStringAttribute("resource");          String url = child.getStringAttribute("url");          String mapperClass = child.getStringAttribute("class");          if (resource != null && url == null && mapperClass == null) {            ErrorContext.instance().resource(resource);            InputStream inputStream = Resources.getResourceAsStream(resource);            XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());            mapperParser.parse();          } else if (resource == null && url != null && mapperClass == null) {            ErrorContext.instance().resource(url);            InputStream inputStream = Resources.getUrlAsStream(url);            XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());            mapperParser.parse();          } else if (resource == null && url == null && mapperClass != null) {            Class
mapperInterface = Resources.classForName(mapperClass); configuration.addMapper(mapperInterface); } else { throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one."); } } } } }

mapper解析细节

// org.apache.ibatis.builder.xml.XMLMapperBuilder.parse() mapper解析细节  public void parse() {    // 只解析一次 namespace    if (!configuration.isResourceLoaded(resource)) {      configurationElement(parser.evalNode("/mapper"));      configuration.addLoadedResource(resource);      bindMapperForNamespace();    }    // 解析 resultMaps    parsePendingResultMaps();    parsePendingCacheRefs();    parsePendingStatements();  }  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);    }  }  private void parsePendingResultMaps() {    Collection
incompleteResultMaps = configuration.getIncompleteResultMaps(); synchronized (incompleteResultMaps) { Iterator
iter = incompleteResultMaps.iterator(); while (iter.hasNext()) { try { iter.next().resolve(); iter.remove(); } catch (IncompleteElementException e) { // ResultMap is still missing a resource... } } } } private void parsePendingCacheRefs() { Collection
incompleteCacheRefs = configuration.getIncompleteCacheRefs(); synchronized (incompleteCacheRefs) { Iterator
iter = incompleteCacheRefs.iterator(); while (iter.hasNext()) { try { iter.next().resolveCacheRef(); iter.remove(); } catch (IncompleteElementException e) { // Cache ref is still missing a resource... } } } } private void parsePendingStatements() { Collection
incompleteStatements = configuration.getIncompleteStatements(); synchronized (incompleteStatements) { Iterator
iter = incompleteStatements.iterator(); while (iter.hasNext()) { try { iter.next().parseStatementNode(); iter.remove(); } catch (IncompleteElementException e) { // Statement is still missing a resource... } } } }
View Code

 

// 最后,返回一个 DefaultSqlSessionFactory, 载入配置项

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

 

// 会话创建好后,可以执行sql了

public void fullyPopulatedSubject() {    // 打开一个连接,使用完成后关闭    try (SqlSession sqlSession = sqlSessionFactory.openSession()) {      final AutoConstructorMapper mapper = sqlSession.getMapper(AutoConstructorMapper.class);      final Object subject = mapper.getSubject(1);      assertNotNull(subject);    }  }

 

2. 打开获得一个数据库会话连接

// org.apache.ibatis.session.defaults.SqlSession.openSession(); 打开一个数据库连接  @Override  public SqlSession openSession() {    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);  }  private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {    Transaction tx = null;    try {        // 运行环境获取      final Environment environment = configuration.getEnvironment();      // 事务管理工厂获取      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);      // 创建新事务      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);      // new Executor      final Executor executor = configuration.newExecutor(tx, execType);      // 最后返回 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();    }  }

 

// org.apache.ibatis.session.Configuration.newExecutor()  public Executor newExecutor(Transaction transaction, ExecutorType executorType) {    executorType = executorType == null ? defaultExecutorType : executorType;    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;    Executor executor;    // 根据不同请求类型创建不同的 executor    if (ExecutorType.BATCH == executorType) {      executor = new BatchExecutor(this, transaction);    } else if (ExecutorType.REUSE == executorType) {      executor = new ReuseExecutor(this, transaction);    } else {      // 默认为 SIMPLE      executor = new SimpleExecutor(this, transaction);    }    if (cacheEnabled) {      // 创建缓存管理,将缓存请求委托给 executor 处理      executor = new CachingExecutor(executor);    }    // 处理plugin 请求    executor = (Executor) interceptorChain.pluginAll(executor);    return executor;  }  // org.apache.ibatis.executor.CachingExecutor  public CachingExecutor(Executor delegate) {    this.delegate = delegate;    delegate.setExecutorWrapper(this);  }    // 最后将加载好的各种配置和实际处理,由 DefaultSqlSession 包装好后返回  public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {    this.configuration = configuration;    this.executor = executor;    this.dirty = false;    this.autoCommit = autoCommit;  }

 

3. 获取mapper,准备调用查询

// org.apache.ibatis.session.defaults.DefaultSqlSession.getMapper()  @Override  public 
T getMapper(Class
type) { return configuration.
getMapper(type, this); } // org.apache.ibatis.binding.MapperRegistry.getMapper() @SuppressWarnings("unchecked") public
T getMapper(Class
type, SqlSession sqlSession) { // 获取 MapperProxyFactory final MapperProxyFactory
mapperProxyFactory = (MapperProxyFactory
) knownMappers.get(type); if (mapperProxyFactory == null) { throw new BindingException("Type " + type + " is not known to the MapperRegistry."); } try { // 创建 mapper 实例 return mapperProxyFactory.newInstance(sqlSession); } catch (Exception e) { throw new BindingException("Error getting mapper instance. Cause: " + e, e); } } // org.apache.ibatis.binding.newInstance(); public T newInstance(SqlSession sqlSession) { final MapperProxy
mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache); return newInstance(mapperProxy); }

 

4. select, 查询数据

//mapper.getSubject(1); 查询数据  @Override  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {    try {      if (Object.class.equals(method.getDeclaringClass())) {        return method.invoke(this, args);      } else if (isDefaultMethod(method)) {        return invokeDefaultMethod(proxy, method, args);      }    } catch (Throwable t) {      throw ExceptionUtil.unwrapThrowable(t);    }    // 加载缓存包装方法    final MapperMethod mapperMethod = cachedMapperMethod(method);    // 执行查询    return mapperMethod.execute(sqlSession, args);  }    private MapperMethod cachedMapperMethod(Method method) {    return methodCache.computeIfAbsent(method, k -> new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));  }  // org.apache.ibatis.binding.MapperMethod.execute(sqlSession, args); 针对不同类型语句,做不同调用  public Object execute(SqlSession sqlSession, Object[] args) {    Object result;    switch (command.getType()) {      case INSERT: {        Object param = method.convertArgsToSqlCommandParam(args);        result = rowCountResult(sqlSession.insert(command.getName(), param));        break;      }      case UPDATE: {        Object param = method.convertArgsToSqlCommandParam(args);        result = rowCountResult(sqlSession.update(command.getName(), param));        break;      }      case DELETE: {        Object param = method.convertArgsToSqlCommandParam(args);        result = rowCountResult(sqlSession.delete(command.getName(), param));        break;      }      case SELECT:        if (method.returnsVoid() && method.hasResultHandler()) {          executeWithResultHandler(sqlSession, args);          result = null;        } else if (method.returnsMany()) {          result = executeForMany(sqlSession, args);        } else if (method.returnsMap()) {          result = executeForMap(sqlSession, args);        } else if (method.returnsCursor()) {          result = executeForCursor(sqlSession, args);        } else {          // 转换参数          Object param = method.convertArgsToSqlCommandParam(args);          // 执行单条查询          result = sqlSession.selectOne(command.getName(), param);          if (method.returnsOptional() &&              (result == null || !method.getReturnType().equals(result.getClass()))) {            result = Optional.ofNullable(result);          }        }        break;      case FLUSH:        result = sqlSession.flushStatements();        break;      default:        throw new BindingException("Unknown execution method for: " + command.getName());    }    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {      throw new BindingException("Mapper method '" + command.getName()           + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");    }    return result;  }

 

// org.apache.ibatis.reflection.ParamNameResolver.getNamedParams() 返回参数,如果是单个参数,直接返回参数值  //  如果是多个参数,则以 map 形式返回  public Object getNamedParams(Object[] args) {    final int paramCount = names.size();    if (args == null || paramCount == 0) {      return null;    } else if (!hasParamAnnotation && paramCount == 1) {      return args[names.firstKey()];    } else {      final Map
param = new ParamMap<>(); int i = 0; for (Map.Entry
entry : names.entrySet()) { param.put(entry.getValue(), args[entry.getKey()]); // add generic param names (param1, param2, ...) final String genericParamName = GENERIC_NAME_PREFIX + String.valueOf(i + 1); // ensure not to overwrite parameter named with @Param if (!names.containsValue(genericParamName)) { param.put(genericParamName, args[entry.getKey()]); } i++; } return param; } }
View Code

 

selectOne

// org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(command.getName(), param);  @Override  public 
T selectOne(String statement, Object parameter) { // Popular vote was to return null on 0 results and throw exception on too many. // 查询单条记录时,默认也是先查询list,然后取第一条 List
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; } } // 查询列表 @Override public
List
selectList(String statement, Object parameter, RowBounds rowBounds) { try { // 先获取执行语句,此处 statement 为 id MappedStatement ms = configuration.getMappedStatement(statement); return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER); } catch (Exception e) { throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } } // org.apache.ibatis.session.Configuration.getMappedStatement(id), 获取初始化解析出来的语句 public MappedStatement getMappedStatement(String id) { return this.getMappedStatement(id, true); } public MappedStatement getMappedStatement(String id, boolean validateIncompleteStatements) { if (validateIncompleteStatements) { buildAllStatements(); } return mappedStatements.get(id); }

 

执行 query

// executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);  // org.apache.ibatis.executor.CachingExecutor.query()  @Override  public 
List
query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { // 获取sql BoundSql boundSql = ms.getBoundSql(parameterObject); CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql); return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); } // org.apache.ibatis.mapping.MappedStatement.getBoundSql() public BoundSql getBoundSql(Object parameterObject) { BoundSql boundSql = sqlSource.getBoundSql(parameterObject); // 字段映射 List
parameterMappings = boundSql.getParameterMappings(); if (parameterMappings == null || parameterMappings.isEmpty()) { boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject); } // check for nested result maps in parameter mappings (issue #30) for (ParameterMapping pm : boundSql.getParameterMappings()) { String rmId = pm.getResultMapId(); if (rmId != null) { ResultMap rm = configuration.getResultMap(rmId); if (rm != null) { hasNestedResultMaps |= rm.hasNestedResultMaps(); } } } return boundSql; } // CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql); // return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); // org.apache.ibatis.executor.CachingExecutor.query() @Override public
List
query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { Cache cache = ms.getCache(); if (cache != null) { flushCacheIfRequired(ms); if (ms.isUseCache() && resultHandler == null) { ensureNoOutParams(ms, boundSql); @SuppressWarnings("unchecked") List
list = (List
) tcm.getObject(cache, key); if (list == null) { list = delegate.
query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); tcm.putObject(cache, key, list); // issue #578 and #116 } return list; } } return delegate.
query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); }

 

queryFromDb

// org.apache.ibatis.executor.SimpleExecutor.query() / BaseExecutor  @SuppressWarnings("unchecked")  @Override  public 
List
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 (closed) { throw new ExecutorException("Executor was closed."); } // 缓存刷新 if (queryStack == 0 && ms.isFlushCacheRequired()) { clearLocalCache(); } List
list; try { queryStack++; list = resultHandler == null ? (List
) localCache.getObject(key) : null; if (list != null) { handleLocallyCachedOutputParameters(ms, key, parameter, boundSql); } else { // 没有缓存,走db list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql); } } finally { queryStack--; } if (queryStack == 0) { for (DeferredLoad deferredLoad : deferredLoads) { deferredLoad.load(); } // issue #601 deferredLoads.clear(); if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) { // issue #482 clearLocalCache(); } } return list; } // BaseExecutor private
List
queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { List
list; // 缓存占位符 localCache.putObject(key, EXECUTION_PLACEHOLDER); try { list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql); } finally { // 防止异常情况,保证将占位缓存删除 localCache.removeObject(key); } // 操作完成后,重新放入缓存 localCache.putObject(key, list); if (ms.getStatementType() == StatementType.CALLABLE) { localOutputParameterCache.putObject(key, parameter); } return list; }

 

doQuery

@Override  public 
List
doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { Statement stmt = null; try { // 获取全局配置 Configuration configuration = ms.getConfiguration(); // 获取statement, 处理 JDBC 接口 StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); stmt = prepareStatement(handler, ms.getStatementLog()); return handler.
query(stmt, resultHandler); } finally { closeStatement(stmt); } } // org.apache.ibatis.session.Configuration.newStatementHandler(), 兼顾 plugins, 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) interceptorChain.pluginAll(statementHandler); return statementHandler; }

 

db查询

// 为不同处理类型,建立不同的 handler  public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {    switch (ms.getStatementType()) {      case STATEMENT:        delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);        break;      case PREPARED:        delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);        break;      case CALLABLE:        delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);        break;      default:        throw new ExecutorException("Unknown statement type: " + ms.getStatementType());    }  }    //stmt = prepareStatement(handler, ms.getStatementLog());  // org.apache.ibatis.executor.SimpleExecutor.prepareStatement(), 获取 statement, JDBC  private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {    Statement stmt;    Connection connection = getConnection(statementLog);    // sql录入    stmt = handler.prepare(connection, transaction.getTimeout());    // 参数绑定    handler.parameterize(stmt);    return stmt;  }    // BaseExecutor  protected Connection getConnection(Log statementLog) throws SQLException {    Connection connection = transaction.getConnection();    if (statementLog.isDebugEnabled()) {      return ConnectionLogger.newInstance(connection, statementLog, queryStack);    } else {      return connection;    }  }  // org.apache.ibatis.transaction.jdbc.JdbcTransaction.getConnection()  @Override  public Connection getConnection() throws SQLException {    if (connection == null) {      // 为空时新建 connection       openConnection();    }    return connection;  }    protected void openConnection() throws SQLException {    if (log.isDebugEnabled()) {      log.debug("Opening JDBC Connection");    }    connection = dataSource.getConnection();    if (level != null) {      connection.setTransactionIsolation(level.getLevel());    }    setDesiredAutoCommit(autoCommit);  }    // org.apache.ibatis.datasource.unpooled.getConnection()  @Override  public Connection getConnection() throws SQLException {    return doGetConnection(username, password);  }  private Connection doGetConnection(String username, String password) throws SQLException {    Properties props = new Properties();    if (driverProperties != null) {      props.putAll(driverProperties);    }    if (username != null) {      props.setProperty("user", username);    }    if (password != null) {      props.setProperty("password", password);    }    return doGetConnection(props);  }    private Connection doGetConnection(Properties properties) throws SQLException {    // 如果没有初始化驱动,初始化    initializeDriver();    //     Connection connection = DriverManager.getConnection(url, properties);    configureConnection(connection);    return connection;  }  private synchronized void initializeDriver() throws SQLException {    if (!registeredDrivers.containsKey(driver)) {      Class
driverType; try { // 加载驱动 if (driverClassLoader != null) { driverType = Class.forName(driver, true, driverClassLoader); } else { driverType = Resources.classForName(driver); } // DriverManager requires the driver to be loaded via the system ClassLoader. // http://www.kfu.com/~nsayer/Java/dyn-jdbc.html Driver driverInstance = (Driver)driverType.newInstance(); DriverManager.registerDriver(new DriverProxy(driverInstance)); registeredDrivers.put(driver, driverInstance); } catch (Exception e) { throw new SQLException("Error setting driver on UnpooledDataSource. Cause: " + e); } } } private void configureConnection(Connection conn) throws SQLException { if (autoCommit != null && autoCommit != conn.getAutoCommit()) { conn.setAutoCommit(autoCommit); } if (defaultTransactionIsolationLevel != null) { conn.setTransactionIsolation(defaultTransactionIsolationLevel); } } // stmt = handler.prepare(connection, transaction.getTimeout()); 组装sql// org.apache.ibatis.executor.statement.RoutingStatementHandler.prepare() @Override public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException { return delegate.prepare(connection, transactionTimeout); } // org.apache.ibatis.executor.statement.PreparedStatementHandler. @Override public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException { ErrorContext.instance().sql(boundSql.getSql()); Statement statement = null; try { // select * from tab where id = ? statement = instantiateStatement(connection); // 设置超时 setStatementTimeout(statement, transactionTimeout); // 设置查询大小,默认不限制 setFetchSize(statement); return statement; } catch (SQLException e) { closeStatement(statement); throw e; } catch (Exception e) { closeStatement(statement); throw new ExecutorException("Error preparing statement. Cause: " + e, e); } } // 调用jdbc connection.prepareStatement(sql), 初始化语句 @Override protected Statement instantiateStatement(Connection connection) throws SQLException { String sql = boundSql.getSql(); if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) { String[] keyColumnNames = mappedStatement.getKeyColumns(); if (keyColumnNames == null) { return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS); } else { return connection.prepareStatement(sql, keyColumnNames); } } else if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) { return connection.prepareStatement(sql); } else { return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY); } } // PreparedStatementHandler handler.parameterize(stmt); @Override public void parameterize(Statement statement) throws SQLException { parameterHandler.setParameters((PreparedStatement) statement); } // org.apache.ibatis.scripting.defaults.DefaultParameterHandler.setParameters() @Override public void setParameters(PreparedStatement ps) { ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId()); List
parameterMappings = boundSql.getParameterMappings(); if (parameterMappings != null) { for (int i = 0; i < parameterMappings.size(); i++) { ParameterMapping parameterMapping = parameterMappings.get(i); if (parameterMapping.getMode() != ParameterMode.OUT) { Object value; String propertyName = parameterMapping.getProperty(); if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params value = boundSql.getAdditionalParameter(propertyName); } else if (parameterObject == null) { value = null; } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { value = parameterObject; } else { MetaObject metaObject = configuration.newMetaObject(parameterObject); value = metaObject.getValue(propertyName); } // TypeHandler 处理参数类型 TypeHandler typeHandler = parameterMapping.getTypeHandler(); JdbcType jdbcType = parameterMapping.getJdbcType(); if (value == null && jdbcType == null) { jdbcType = configuration.getJdbcTypeForNull(); } try { typeHandler.setParameter(ps, i + 1, value, jdbcType); } catch (TypeException e) { throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e); } catch (SQLException e) { throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e); } } } } } // return handler.
query(stmt, resultHandler); // org.apache.ibatis.executor.statement.RoutingStatementHandler.query() @Override public
List
query(Statement statement, ResultHandler resultHandler) throws SQLException { return delegate.
query(statement, resultHandler); } // PreparedStatementHandler.query() @Override public
List
query(Statement statement, ResultHandler resultHandler) throws SQLException { PreparedStatement ps = (PreparedStatement) statement; // 调用驱动程序执行 execute ps.execute(); // 处理结果集映射 return resultSetHandler.
handleResultSets(ps); } // org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(), 处理结果集映射 @Override public List
handleResultSets(Statement stmt) throws SQLException { ErrorContext.instance().activity("handling results").object(mappedStatement.getId()); final List multipleResults = new ArrayList<>(); int resultSetCount = 0; // 获取第一个结果集(开始偏移的地方) ResultSetWrapper rsw = getFirstResultSet(stmt); List
resultMaps = mappedStatement.getResultMaps(); int resultMapCount = resultMaps.size(); validateResultMapsCount(rsw, resultMapCount); while (rsw != null && resultMapCount > resultSetCount) { ResultMap resultMap = resultMaps.get(resultSetCount); handleResultSet(rsw, resultMap, multipleResults, null); rsw = getNextResultSet(stmt); cleanUpAfterHandlingResultSet(); resultSetCount++; } String[] resultSets = mappedStatement.getResultSets(); if (resultSets != null) { while (rsw != null && resultSetCount < resultSets.length) { ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]); if (parentMapping != null) { String nestedResultMapId = parentMapping.getNestedResultMapId(); ResultMap resultMap = configuration.getResultMap(nestedResultMapId); handleResultSet(rsw, resultMap, null, parentMapping); } rsw = getNextResultSet(stmt); cleanUpAfterHandlingResultSet(); resultSetCount++; } } return collapseSingleResultList(multipleResults); } // org.apache.ibatis.executor.resultset.ResultSetWrapper, 根据第一行返回数据集,初始化字段名及字段类型 public ResultSetWrapper(ResultSet rs, Configuration configuration) throws SQLException { super(); this.typeHandlerRegistry = configuration.getTypeHandlerRegistry(); this.resultSet = rs; final ResultSetMetaData metaData = rs.getMetaData(); final int columnCount = metaData.getColumnCount(); for (int i = 1; i <= columnCount; i++) { columnNames.add(configuration.isUseColumnLabel() ? metaData.getColumnLabel(i) : metaData.getColumnName(i)); // java.sql.Types, 处理返回的类型为具体的java类型映射到 org.apache.ibatis.type.JdbcType jdbcTypes.add(JdbcType.forCode(metaData.getColumnType(i))); // java 类型全名 classNames.add(metaData.getColumnClassName(i)); } }
View Code

 

数据库结果映射到javabean

// DefaultResultSetHandler.handleResultSet() 处理单条记录映射关系  private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List multipleResults, ResultMapping parentMapping) throws SQLException {    try {      if (parentMapping != null) {        handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);      } else {        if (resultHandler == null) {          DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);          handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);          multipleResults.add(defaultResultHandler.getResultList());        } else {          handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);        }      }    } finally {      // issue #228 (close resultsets)      closeResultSet(rsw.getResultSet());    }  }  // handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);  public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler
resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException { if (resultMap.hasNestedResultMaps()) { // 嵌套数据的映射 ensureNoRowBounds(); checkResultHandler(); handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping); } else { // 简单数据映射 handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping); } } // 简单数据映射 private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler
resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException { DefaultResultContext resultContext = new DefaultResultContext<>(); ResultSet resultSet = rsw.getResultSet(); // 跳过行偏移,难道不是在数据sql中添加 limit 进行数据筛选的? skipRows(resultSet, rowBounds); while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) { // 1. Discriminated 鉴别器 ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null); // Object rowValue = getRowValue(rsw, discriminatedResultMap, null); storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet); } } // 检测超过 limit 后,不再继续获取结果 private boolean shouldProcessMoreRows(ResultContext
context, RowBounds rowBounds) { return !context.isStopped() && context.getResultCount() < rowBounds.getLimit(); } // Discriminated public ResultMap resolveDiscriminatedResultMap(ResultSet rs, ResultMap resultMap, String columnPrefix) throws SQLException { Set
pastDiscriminators = new HashSet<>(); Discriminator discriminator = resultMap.getDiscriminator(); while (discriminator != null) { final Object value = getDiscriminatorValue(rs, discriminator, columnPrefix); final String discriminatedMapId = discriminator.getMapIdFor(String.valueOf(value)); if (configuration.hasResultMap(discriminatedMapId)) { resultMap = configuration.getResultMap(discriminatedMapId); Discriminator lastDiscriminator = discriminator; discriminator = resultMap.getDiscriminator(); if (discriminator == lastDiscriminator || !pastDiscriminators.add(discriminatedMapId)) { break; } } else { break; } } return resultMap; } // 从结果set中获取值 private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException { final ResultLoaderMap lazyLoader = new ResultLoaderMap(); Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix); if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) { final MetaObject metaObject = configuration.newMetaObject(rowValue); boolean foundValues = this.useConstructorMappings; if (shouldApplyAutomaticMappings(resultMap, false)) { foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues; } foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues; foundValues = lazyLoader.size() > 0 || foundValues; rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null; } return rowValue; } // DefaultResultSetHandler private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List
> constructorArgTypes, List
constructorArgs, String columnPrefix) throws SQLException { final Class
resultType = resultMap.getType(); final MetaClass metaType = MetaClass.forClass(resultType, reflectorFactory); final List
constructorMappings = resultMap.getConstructorResultMappings(); if (hasTypeHandlerForResultObject(rsw, resultType)) { return createPrimitiveResultObject(rsw, resultMap, columnPrefix); } else if (!constructorMappings.isEmpty()) { return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes, constructorArgs, columnPrefix); } else if (resultType.isInterface() || metaType.hasDefaultConstructor()) { return objectFactory.create(resultType); } else if (shouldApplyAutomaticMappings(resultMap, false)) { return createByConstructorSignature(rsw, resultType, constructorArgTypes, constructorArgs, columnPrefix); } throw new ExecutorException("Do not know how to create an instance of " + resultType); } // 构造器注入方式 private Object createByConstructorSignature(ResultSetWrapper rsw, Class
resultType, List
> constructorArgTypes, List
constructorArgs, String columnPrefix) throws SQLException { final Constructor
[] constructors = resultType.getDeclaredConstructors(); final Constructor
defaultConstructor = findDefaultConstructor(constructors); if (defaultConstructor != null) { return createUsingConstructor(rsw, resultType, constructorArgTypes, constructorArgs, columnPrefix, defaultConstructor); } else { for (Constructor
constructor : constructors) { if (allowedConstructorUsingTypeHandlers(constructor, rsw.getJdbcTypes())) { return createUsingConstructor(rsw, resultType, constructorArgTypes, constructorArgs, columnPrefix, constructor); } } } throw new ExecutorException("No constructor found in " + resultType.getName() + " matching " + rsw.getClassNames()); } private Object createUsingConstructor(ResultSetWrapper rsw, Class
resultType, List
> constructorArgTypes, List
constructorArgs, String columnPrefix, Constructor
constructor) throws SQLException { boolean foundValues = false; for (int i = 0; i < constructor.getParameterTypes().length; i++) { Class
parameterType = constructor.getParameterTypes()[i]; String columnName = rsw.getColumnNames().get(i); TypeHandler
typeHandler = rsw.getTypeHandler(parameterType, columnName); Object value = typeHandler.getResult(rsw.getResultSet(), prependPrefix(columnName, columnPrefix)); constructorArgTypes.add(parameterType); constructorArgs.add(value); foundValues = value != null || foundValues; } // 调用构造方法注入值 return foundValues ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : null; }

 

// org.apache.ibatis.reflection.factory.DefaultObjectFactory.create(), 调用构造器返回 bean 实例  @SuppressWarnings("unchecked")  @Override  public 
T create(Class
type, List
> constructorArgTypes, List
constructorArgs) { Class
classToCreate = resolveInterface(type); // we know types are assignable return (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs); } private
T instantiateClass(Class
type, List
> constructorArgTypes, List
constructorArgs) { try { Constructor
constructor; if (constructorArgTypes == null || constructorArgs == null) { constructor = type.getDeclaredConstructor(); try { return constructor.newInstance(); } catch (IllegalAccessException e) { if (Reflector.canControlMemberAccessible()) { constructor.setAccessible(true); return constructor.newInstance(); } else { throw e; } } } constructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[constructorArgTypes.size()])); try { return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()])); } catch (IllegalAccessException e) { if (Reflector.canControlMemberAccessible()) { constructor.setAccessible(true); return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()])); } else { throw e; } } } catch (Exception e) { StringBuilder argTypes = new StringBuilder(); if (constructorArgTypes != null && !constructorArgTypes.isEmpty()) { for (Class
argType : constructorArgTypes) { argTypes.append(argType.getSimpleName()); argTypes.append(","); } argTypes.deleteCharAt(argTypes.length() - 1); // remove trailing , } StringBuilder argValues = new StringBuilder(); if (constructorArgs != null && !constructorArgs.isEmpty()) { for (Object argValue : constructorArgs) { argValues.append(String.valueOf(argValue)); argValues.append(","); } argValues.deleteCharAt(argValues.length() - 1); // remove trailing , } throw new ReflectionException("Error instantiating " + type + " with invalid types (" + argTypes + ") or values (" + argValues + "). Cause: " + e, e); } }
View Code

 

数据集获取

// 保存结果  private void storeObject(ResultHandler
resultHandler, DefaultResultContext resultContext, Object rowValue, ResultMapping parentMapping, ResultSet rs) throws SQLException { if (parentMapping != null) { linkToParents(rs, parentMapping, rowValue); } else { callResultHandler(resultHandler, resultContext, rowValue); } } @SuppressWarnings("unchecked" /* because ResultHandler
is always ResultHandler*/) private void callResultHandler(ResultHandler
resultHandler, DefaultResultContext resultContext, Object rowValue) { resultContext.nextResultObject(rowValue); ((ResultHandler) resultHandler).handleResult(resultContext); } // private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException { final List
mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix); boolean foundValues = false; final List
propertyMappings = resultMap.getPropertyResultMappings(); for (ResultMapping propertyMapping : propertyMappings) { String column = prependPrefix(propertyMapping.getColumn(), columnPrefix); if (propertyMapping.getNestedResultMapId() != null) { // the user added a column attribute to a nested result map, ignore it column = null; } if (propertyMapping.isCompositeResult() || (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH))) || propertyMapping.getResultSet() != null) { Object value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix); // issue #541 make property optional final String property = propertyMapping.getProperty(); if (property == null) { continue; } else if (value == DEFERED) { foundValues = true; continue; } if (value != null) { foundValues = true; } if (value != null || (configuration.isCallSettersOnNulls() && !metaObject.getSetterType(property).isPrimitive())) { // gcode issue #377, call setter on nulls (value is not 'found') metaObject.setValue(property, value); } } } return foundValues; } // collapseSingleResultList(multipleResults); 转换多级 list 为1级list @SuppressWarnings("unchecked") private List
collapseSingleResultList(List multipleResults) { return multipleResults.size() == 1 ? (List) multipleResults.get(0) : multipleResults; }

 

至此,一条select 语句搞定!

主要经历几个阶段:

  1. 加载配置
  2. 创建sqlSessionFactory
  3. 获取sqlSession
  4. jdbc连接
  5. 获取mapper
  6. 查询参数绑定
  7. 获取db结果
  8. 处理返回集字段映射
  9. 缓存结果
  10. 返回结果

转载地址:http://zugfm.baihongyu.com/

你可能感兴趣的文章
BZOJ-4260-Codechef REBXOR(trie树)
查看>>
洛谷OJ P1379 八数码难题 解题报告
查看>>
MySQL练习题
查看>>
Cucumber 入门【转】
查看>>
JDBC为什么要使用PreparedStatement而不是Statement
查看>>
【python3的学习之路一】输入和输出
查看>>
关于ST-Link的internal command error问题的解决方法
查看>>
[整理] 两种方法查看MFC源代码
查看>>
字符常量 java
查看>>
面试中,应聘者问面试官的问题
查看>>
用js实现翻牌的效果
查看>>
Linux 中文设置
查看>>
再写mock对象
查看>>
hg vs git :这个世界除了svn还有别的
查看>>
BZOJ1095:[ZJOI2007]Hide 捉迷藏(动态点分治)
查看>>
[LeetCode] Word Break II
查看>>
两句话解决代理问题
查看>>
熊市中,值得关注的项目都有这三大特征
查看>>
2018.12.27-dtoj-4089-line
查看>>
10:比较整数大小经典案例
查看>>