内容简介:1. 下载git仓库, https://github.com/mybatis/mybatis-32. 打开IDE, 找到 test 包3. 进入 org.apache.ibatis.autoconstructor.AutoConstructorTest, 有一个完整的sql 样例
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<? extends VFS> vfsImpl = (Class<? extends VFS>)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<Interceptor> 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<Interceptor> 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<? extends TypeHandler> typeHandler = (Class<? extends TypeHandler>)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<? extends Log> logImpl = (Class<? extends Log>)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<JdbcType, TypeHandler<?>> 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<ResultMapResolver> incompleteResultMaps = configuration.getIncompleteResultMaps(); synchronized (incompleteResultMaps) { Iterator<ResultMapResolver> 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<CacheRefResolver> incompleteCacheRefs = configuration.getIncompleteCacheRefs(); synchronized (incompleteCacheRefs) { Iterator<CacheRefResolver> 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<XMLStatementBuilder> incompleteStatements = configuration.getIncompleteStatements(); synchronized (incompleteStatements) { Iterator<XMLStatementBuilder> 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> T getMapper(Class<T> type) { return configuration.<T>getMapper(type, this); } // org.apache.ibatis.binding.MapperRegistry.getMapper() @SuppressWarnings("unchecked") public <T> T getMapper(Class<T> type, SqlSession sqlSession) { // 获取 MapperProxyFactory final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) 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<T> 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<String, Object> param = new ParamMap<>(); int i = 0; for (Map.Entry<Integer, String> 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> T selectOne(String statement, Object parameter) { // Popular vote was to return null on 0 results and throw exception on too many. // 查询单条记录时,默认也是先查询list,然后取第一条 List<T> list = this.<T>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 <E> List<E> 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 <E> List<E> 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<ParameterMapping> 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 <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { Cache cache = ms.getCache(); if (cache != null) { flushCacheIfRequired(ms); if (ms.isUseCache() && resultHandler == null) { ensureNoOutParams(ms, boundSql); @SuppressWarnings("unchecked") List<E> list = (List<E>) tcm.getObject(cache, key); if (list == null) { list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); tcm.putObject(cache, key, list); // issue #578 and #116 } return list; } } return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); }
queryFromDb
// org.apache.ibatis.executor.SimpleExecutor.query() / BaseExecutor @SuppressWarnings("unchecked") @Override 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 (closed) { throw new ExecutorException("Executor was closed."); } // 缓存刷新 if (queryStack == 0 && ms.isFlushCacheRequired()) { clearLocalCache(); } List<E> list; try { queryStack++; list = resultHandler == null ? (List<E>) 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 <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { List<E> 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 <E> List<E> 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.<E>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<ParameterMapping> 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.<E>query(stmt, resultHandler); // org.apache.ibatis.executor.statement.RoutingStatementHandler.query() @Override public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException { return delegate.<E>query(statement, resultHandler); } // PreparedStatementHandler.query() @Override public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException { PreparedStatement ps = (PreparedStatement) statement; // 调用驱动程序执行 execute ps.execute(); // 处理结果集映射 return resultSetHandler.<E> handleResultSets(ps); } // org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(), 处理结果集映射 @Override public List<Object> handleResultSets(Statement stmt) throws SQLException { ErrorContext.instance().activity("handling results").object(mappedStatement.getId()); final List<Object> multipleResults = new ArrayList<>(); int resultSetCount = 0; // 获取第一个结果集(开始偏移的地方) ResultSetWrapper rsw = getFirstResultSet(stmt); List<ResultMap> 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<Object> 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<Object> 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<String> 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<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix) throws SQLException { final Class<?> resultType = resultMap.getType(); final MetaClass metaType = MetaClass.forClass(resultType, reflectorFactory); final List<ResultMapping> 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<Class<?>> constructorArgTypes, List<Object> 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<Class<?>> constructorArgTypes, List<Object> 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> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) { Class<?> classToCreate = resolveInterface(type); // we know types are assignable return (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs); } private <T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) { try { Constructor<T> 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<Object> 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<Object>*/) private void callResultHandler(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue) { resultContext.nextResultObject(rowValue); ((ResultHandler<Object>) resultHandler).handleResult(resultContext); } // private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException { final List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix); boolean foundValues = false; final List<ResultMapping> 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<Object> collapseSingleResultList(List<Object> multipleResults) { return multipleResults.size() == 1 ? (List<Object>) multipleResults.get(0) : multipleResults; }
至此,一条select 语句搞定!
主要经历几个阶段:
1. 加载配置
2. 创建sqlSessionFactory
3. 获取sqlSession
4. jdbc连接
5. 获取mapper
6. 查询参数绑定
7. 获取db结果
8. 处理返回集字段映射
9. 缓存结果
10. 返回结果
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 一个需求的一生
- 一个付费 Chrome 插件的一生
- 被嫌弃的程序员的一生
- 值得一生典藏:MySQL的事务实现原理
- 一个像素的一生:剖析 Chromium 渲染流水线
- 程序的一生:从源程序到进程的辛苦历程
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Web Designer's Idea Book
Patrick Mcneil / How / 2008-10-6 / USD 25.00
The Web Designer's Idea Book includes more than 700 websites arranged thematically, so you can find inspiration for layout, color, style and more. Author Patrick McNeil has cataloged more than 5,000 s......一起来看看 《The Web Designer's Idea Book》 这本书的介绍吧!
XML 在线格式化
在线 XML 格式化压缩工具
html转js在线工具
html转js在线工具