mybatis的基础使用类似下面的代码
public static void main(String[] args) throws IOException {
InputStream is = Resources.getResourceAsStream("");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession();
PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
mapper.findAll();
sqlSession.close();
}
这一篇分析mybatis构建SqlSessionFactory的源码分析,其中包括创建SqlSessionFactory和其相关的配置文件,mapper的解析,本篇有点长
使用了builder构造SqlSessionFactory
//org.apache.ibatis.session.SqlSessionFactoryBuilder#build(java.io.InputStream)
public SqlSessionFactory build(InputStream inputStream) {
return build(inputStream, null, null);
}
//org.apache.ibatis.session.SqlSessionFactoryBuilder#build
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
//创建一个解析器,用来解析配置文件,sql的xml文件
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
//解析xml文件,并且构建SqlSessionFactory
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
//org.apache.ibatis.session.SqlSessionFactoryBuilder#build
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
//org.apache.ibatis.session.defaults.DefaultSqlSessionFactory
private final Configuration configuration;
public DefaultSqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
}
配置文件的解析
创建解析器
//org.apache.ibatis.builder.xml.XMLConfigBuilder#XMLConfigBuilder
public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
super(new Configuration());
ErrorContext.instance().resource("SQL Mapper Configuration");
this.configuration.setVariables(props);
this.parsed = false;
this.environment = environment;
this.parser = parser;
}
//调用XMLConfigBuilder抽象父类BaseBuilder的构造器
//org.apache.ibatis.builder.BaseBuilder#BaseBuilder
//这个类只有这三个属性
public BaseBuilder(Configuration configuration) {
this.configuration = configuration;
this.typeAliasRegistry = this.configuration.getTypeAliasRegistry();
this.typeHandlerRegistry = this.configuration.getTypeHandlerRegistry();
}
创建Configration,Configration的构造器以及一些属性
//Configration的一些属性
//mybatis环境
protected Environment environment;
//用来生成mapper
protected final MapperRegistry mapperRegistry = new MapperRegistry(this);
//拦截器链,插件用拦截器实现
protected final InterceptorChain interceptorChain = new InterceptorChain();
//类型处理器注册
protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry(this);
//别名注册
protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();
protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry();
//sql配置
protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection")
.conflictMessageProducer((savedValue, targetValue) ->
". please check " + savedValue.getResource() + " and " + targetValue.getResource());
//缓存
protected final Map<String, Cache> caches = new StrictMap<>("Caches collection");
//结果集
protected final Map<String, ResultMap> resultMaps = new StrictMap<>("Result Maps collection");
//参数集
protected final Map<String, ParameterMap> parameterMaps = new StrictMap<>("Parameter Maps collection");
//主键生成器
protected final Map<String, KeyGenerator> keyGenerators = new StrictMap<>("Key Generators collection");
protected final Set<String> loadedResources = new HashSet<>();
protected final Map<String, XNode> sqlFragments = new StrictMap<>("XML fragments parsed from previous mappers");
protected final Collection<XMLStatementBuilder> incompleteStatements = new LinkedList<>();
protected final Collection<CacheRefResolver> incompleteCacheRefs = new LinkedList<>();
protected final Collection<ResultMapResolver> incompleteResultMaps = new LinkedList<>();
protected final Collection<MethodResolver> incompleteMethods = new LinkedList<>();
//Configration构造器
public Configuration() {
// 为类型注册别名
typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);
typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);
typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);
typeAliasRegistry.registerAlias("FIFO", FifoCache.class);
typeAliasRegistry.registerAlias("LRU", LruCache.class);
typeAliasRegistry.registerAlias("SOFT", SoftCache.class);
typeAliasRegistry.registerAlias("WEAK", WeakCache.class);
typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);
typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);
typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class);
typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);
typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);
typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class);
languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);
languageRegistry.register(RawLanguageDriver.class);
}
解析xml文件
//org.apache.ibatis.builder.xml.XMLConfigBuilder#parse
public Configuration parse() {
//解析过了,抛异常
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
//标记已经解析过了
parsed = true;
//解析配置,传入根元素
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
解析配置
//org.apache.ibatis.builder.xml.XMLConfigBuilder#parseConfiguration
private void parseConfiguration(XNode root) {
try {
//解析配置文件各种标签
propertiesElement(root.evalNode("properties"));
//解析setting标签
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"));
//给setting的子标签赋值
settingsElement(settings);
//创建数据源
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);
}
}
创建数据源
//org.apache.ibatis.builder.xml.XMLConfigBuilder#environmentsElement
private void environmentsElement(XNode context) throws Exception {
if (context != null) {
if (environment == null) {
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
Environment.Builder environmentBuilder = new Environment.Builder(id)
.transactionFactory(txFactory)
.dataSource(dataSource);
// 放入 Configuration
configuration.setEnvironment(environmentBuilder.build());
}
}
}
}
//创建数据源工厂
//org.apache.ibatis.builder.xml.XMLConfigBuilder#dataSourceElement
private DataSourceFactory dataSourceElement(XNode context) throws Exception {
if (context != null) {
//dataSource标签的子标签
String type = context.getStringAttribute("type");
Properties props = context.getChildrenAsProperties();
//根据具体类型实例化数据源工厂
DataSourceFactory factory = (DataSourceFactory) resolveClass(type).getDeclaredConstructor().newInstance();
factory.setProperties(props);
return factory;
}
throw new BuilderException("Environment declaration requires a DataSourceFactory.");
}
//获取数据源工厂的具体类型
//org.apache.ibatis.builder.BaseBuilder#resolveClass
protected <T> Class<? extends T> resolveClass(String alias) {
if (alias == null) {
return null;
}
try {
return resolveAlias(alias);
} catch (Exception e) {
throw new BuilderException("Error resolving class. Cause: " + e, e);
}
}
//从别名注册器中获取具体的类型
//org.apache.ibatis.builder.BaseBuilder#resolveAlias
protected <T> Class<? extends T> resolveAlias(String alias) {
return typeAliasRegistry.resolveAlias(alias);
}
解析typeHandlers标签,注册typeHandler
//org.apache.ibatis.builder.xml.XMLConfigBuilder#typeHandlerElement
private void typeHandlerElement(XNode parent) {
if (parent != null) {
for (XNode child : parent.getChildren()) {
if ("package".equals(child.getName())) {
String typeHandlerPackage = child.getStringAttribute("name");
typeHandlerRegistry.register(typeHandlerPackage);
} else {
//Java类型名称
String javaTypeName = child.getStringAttribute("javaType");
//jdbc类型名称
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);
}
}
}
}
}
解析mapper
//org.apache.ibatis.builder.xml.XMLConfigBuilder#mapperElement
private void mapperElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child : parent.getChildren()) {
// package 包
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) {
// resource 相对路径
ErrorContext.instance().resource(resource);
InputStream inputStream = Resources.getResourceAsStream(resource);
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
// 解析 Mapper.xml,总体上做了两件事情 >>
mapperParser.parse();
} else if (resource == null && url != null && mapperClass == null) {
// url 绝对路径
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 单个接口
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.session.Configuration#addMappers(java.lang.String)
public void addMappers(String packageName) {
mapperRegistry.addMappers(packageName);
}
//org.apache.ibatis.binding.MapperRegistry#addMappers(java.lang.String)
public void addMappers(String packageName) {
addMappers(packageName, Object.class);
}
//org.apache.ibatis.binding.MapperRegistry#addMappers
public void addMappers(String packageName, Class<?> superType) {
ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>();
resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
//从包中获取所有的mapper
Set<Class<? extends Class<?>>> mapperSet = resolverUtil.getClasses();
// 循环添加
for (Class<?> mapperClass : mapperSet) {
addMapper(mapperClass);
}
}
添加mapper
//org.apache.ibatis.binding.MapperRegistry#addMapper
public <T> void addMapper(Class<T> type) {
//只有接口才会被处理
if (type.isInterface()) {
//已经添加过该mapper了
if (hasMapper(type)) {
throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
}
boolean loadCompleted = false;
try {
//private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<>();
//存放的是接口类型,和对应的工厂类的关系
knownMappers.put(type, new MapperProxyFactory<>(type));
//mapper类型注册应该早于mapper的解析
// 注册了接口之后,根据接口,开始解析所有方法上的注解,例如 @Select >>
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
parser.parse();
loadCompleted = true;
} finally {
if (!loadCompleted) {
knownMappers.remove(type);
}
}
}
}
解析mapper
//org.apache.ibatis.builder.annotation.MapperAnnotationBuilder#parse
public void parse() {
String resource = type.toString();
if (!configuration.isResourceLoaded(resource)) {
// 先判断 Mapper.xml 有没有解析,没有的话先解析 Mapper.xml(例如定义 package 方式)
loadXmlResource();
configuration.addLoadedResource(resource);
assistant.setCurrentNamespace(type.getName());
// 处理 @CacheNamespace
parseCache();
// 处理 @CacheNamespaceRef
parseCacheRef();
// 获取所有方法
Method[] methods = type.getMethods();
for (Method method : methods) {
try {
// issue #237
if (!method.isBridge()) {
// 解析方法上的注解,添加到 MappedStatement 集合中 >>
parseStatement(method);
}
} catch (IncompleteElementException e) {
configuration.addIncompleteMethod(new MethodResolver(this, method));
}
}
}
parsePendingMethods();
}
加载mapper.xml资源
//org.apache.ibatis.builder.annotation.MapperAnnotationBuilder#loadXmlResource
private void loadXmlResource() {
// Spring 不知道真正的资源名字,所以添加了一个标志防止资源被加载两次
// 标记在这里 XMLMapperBuilder#bindMapperForNamespace
if (!configuration.isResourceLoaded("namespace:" + type.getName())) {
String xmlResource = type.getName().replace('.', '/') + ".xml";
// #1347 加载mapper.xml
InputStream inputStream = type.getResourceAsStream("/" + xmlResource);
if (inputStream == null) {
// 从classpath下加载mapper.xml
try {
inputStream = Resources.getResourceAsStream(type.getClassLoader(), xmlResource);
} catch (IOException e2) {
// ignore, resource is not required
}
}
if (inputStream != null) {
//构建mapper解析器
XMLMapperBuilder xmlParser = new XMLMapperBuilder(inputStream, assistant.getConfiguration(), xmlResource, configuration.getSqlFragments(), type.getName());
// 解析 Mapper.xml >>
xmlParser.parse();
}
}
}
解析mappe.xml
//org.apache.ibatis.builder.xml.XMLMapperBuilder#parse
public void parse() {
// 资源还没有被加载
//protected final Set<String> loadedResources = new HashSet<>();
if (!configuration.isResourceLoaded(resource)) {
// 具体增删改查标签的解析。 一个标签一个MappedStatement
configurationElement(parser.evalNode("/mapper"));
//标记该资源已经被加载
configuration.addLoadedResource(resource);
// 2、把namespace(接口类型)和工厂类绑定起来,放到一个map。
// 一个namespace 一个 MapperProxyFactory >>
bindMapperForNamespace();
}
parsePendingResultMaps();
parsePendingCacheRefs();
parsePendingStatements();
}
解析mapper标签
private void configurationElement(XNode context) {
try {
//解析namespace
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"));
// 解析 cache 属性,添加缓存对象
cacheElement(context.evalNode("cache"));
// 创建 ParameterMapping 对象
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
// 创建 List<ResultMapping>
resultMapElements(context.evalNodes("/mapper/resultMap"));
// 解析可以复用的SQL
sqlElement(context.evalNodes("/mapper/sql"));
// 解析增删改查标签,得到 MappedStatement
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);
}
}
创建 ParameterMapping 对象
//org.apache.ibatis.builder.xml.XMLMapperBuilder#parameterMapElement
private void parameterMapElement(List<XNode> list) {
for (XNode parameterMapNode : list) {
//获取id
String id = parameterMapNode.getStringAttribute("id");
//获取type
String type = parameterMapNode.getStringAttribute("type");
//解析type对应的类
Class<?> parameterClass = resolveClass(type);
//获取参数类型
List<XNode> parameterNodes = parameterMapNode.evalNodes("parameter");
List<ParameterMapping> parameterMappings = new ArrayList<>();
//循环遍历所有的参数
for (XNode parameterNode : parameterNodes) {
//获取属性名称
String property = parameterNode.getStringAttribute("property");
//获取Java类型
String javaType = parameterNode.getStringAttribute("javaType");
//获取jdbc类型
String jdbcType = parameterNode.getStringAttribute("jdbcType");
//获取resultMap的名称
String resultMap = parameterNode.getStringAttribute("resultMap");
//获取模式
String mode = parameterNode.getStringAttribute("mode");
//获取类型处理器
String typeHandler = parameterNode.getStringAttribute("typeHandler");
Integer numericScale = parameterNode.getIntAttribute("numericScale");
//解析模式枚举 IN, OUT, INOUT
ParameterMode modeEnum = resolveParameterMode(mode);
//解析Java类型的类
Class<?> javaTypeClass = resolveClass(javaType);
//解析jdbc类型的类
JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
//解析类型处理器的类
Class<? extends TypeHandler<?>> typeHandlerClass = resolveClass(typeHandler);
//建立parameterMapping并加入parameterMappings
ParameterMapping parameterMapping = builderAssistant.buildParameterMapping(parameterClass, property, javaTypeClass, jdbcTypeEnum, resultMap, modeEnum, typeHandlerClass, numericScale);
parameterMappings.add(parameterMapping);
}
builderAssistant.addParameterMap(id, parameterClass, parameterMappings);
}
}
//添加parameterMap
//protected final Map<String, ParameterMap> parameterMaps = new StrictMap<>("Parameter Maps collection");
//org.apache.ibatis.builder.MapperBuilderAssistant#addParameterMap
public ParameterMap addParameterMap(String id, Class<?> parameterClass, List<ParameterMapping> parameterMappings) {
id = applyCurrentNamespace(id, false);
ParameterMap parameterMap = new ParameterMap.Builder(configuration, id, parameterClass, parameterMappings).build();
configuration.addParameterMap(parameterMap);
return parameterMap;
}
创建resultMappings
//org.apache.ibatis.builder.xml.XMLMapperBuilder#resultMapElements
private void resultMapElements(List<XNode> list) {
for (XNode resultMapNode : list) {
try {
resultMapElement(resultMapNode);
} catch (IncompleteElementException e) {
// ignore, it will be retried
}
}
}
//org.apache.ibatis.builder.xml.XMLMapperBuilder#resultMapElement
private ResultMap resultMapElement(XNode resultMapNode) {
return resultMapElement(resultMapNode, Collections.emptyList(), null);
}
//org.apache.ibatis.builder.xml.XMLMapperBuilder#resultMapElement
private ResultMap resultMapElement(XNode resultMapNode, List<ResultMapping> additionalResultMappings, Class<?> enclosingType) {
ErrorContext.instance().activity("processing " + resultMapNode.getValueBasedIdentifier());
//获取四中之一的名称
String type = resultMapNode.getStringAttribute("type",
resultMapNode.getStringAttribute("ofType",
resultMapNode.getStringAttribute("resultType",
resultMapNode.getStringAttribute("javaType"))));
//解析类型
Class<?> typeClass = resolveClass(type);
if (typeClass == null) {
typeClass = inheritEnclosingType(resultMapNode, enclosingType);
}
Discriminator discriminator = null;
List<ResultMapping> resultMappings = new ArrayList<>(additionalResultMappings);
List<XNode> resultChildren = resultMapNode.getChildren();
//循环遍历子节点
for (XNode resultChild : resultChildren) {
if ("constructor".equals(resultChild.getName())) {
processConstructorElement(resultChild, typeClass, resultMappings);
} else if ("discriminator".equals(resultChild.getName())) {
discriminator = processDiscriminatorElement(resultChild, typeClass, resultMappings);
} else {
List<ResultFlag> flags = new ArrayList<>();
if ("id".equals(resultChild.getName())) {
flags.add(ResultFlag.ID);
}
//构建resuntMapping并添加到resultMappings
resultMappings.add(buildResultMappingFromContext(resultChild, typeClass, flags));
}
}
//获取id
String id = resultMapNode.getStringAttribute("id",
resultMapNode.getValueBasedIdentifier());
String extend = resultMapNode.getStringAttribute("extends");
Boolean autoMapping = resultMapNode.getBooleanAttribute("autoMapping");
//生成resultMapping解析器
ResultMapResolver resultMapResolver = new ResultMapResolver(builderAssistant, id, typeClass, extend, discriminator, resultMappings, autoMapping);
try {
return resultMapResolver.resolve();
} catch (IncompleteElementException e) {
configuration.addIncompleteResultMap(resultMapResolver);
throw e;
}
}
//org.apache.ibatis.builder.ResultMapResolver#resolve
public ResultMap resolve() {
return assistant.addResultMap(this.id, this.type, this.extend, this.discriminator, this.resultMappings, this.autoMapping);
}
//添加resultMap
//org.apache.ibatis.builder.MapperBuilderAssistant#addResultMap
public ResultMap addResultMap(
String id,
Class<?> type,
String extend,
Discriminator discriminator,
List<ResultMapping> resultMappings,
Boolean autoMapping) {
id = applyCurrentNamespace(id, false);
extend = applyCurrentNamespace(extend, true);
if (extend != null) {
if (!configuration.hasResultMap(extend)) {
throw new IncompleteElementException("Could not find a parent resultmap with id '" + extend + "'");
}
ResultMap resultMap = configuration.getResultMap(extend);
List<ResultMapping> extendedResultMappings = new ArrayList<>(resultMap.getResultMappings());
extendedResultMappings.removeAll(resultMappings);
// Remove parent constructor if this resultMap declares a constructor.
boolean declaresConstructor = false;
for (ResultMapping resultMapping : resultMappings) {
if (resultMapping.getFlags().contains(ResultFlag.CONSTRUCTOR)) {
declaresConstructor = true;
break;
}
}
if (declaresConstructor) {
extendedResultMappings.removeIf(resultMapping -> resultMapping.getFlags().contains(ResultFlag.CONSTRUCTOR));
}
resultMappings.addAll(extendedResultMappings);
}
ResultMap resultMap = new ResultMap.Builder(configuration, id, type, resultMappings, autoMapping)
.discriminator(discriminator)
.build();
configuration.addResultMap(resultMap);
return resultMap;
}
//org.apache.ibatis.session.Configuration#addResultMap
//protected final Map<String, ResultMap> resultMaps = new StrictMap<>("Result Maps collection");
public void addResultMap(ResultMap rm) {
resultMaps.put(rm.getId(), rm);
checkLocallyForDiscriminatedNestedResultMaps(rm);
checkGloballyForDiscriminatedNestedResultMaps(rm);
}
创建Statement
//org.apache.ibatis.builder.xml.XMLMapperBuilder#buildStatementFromContext
private void buildStatementFromContext(List<XNode> list) {
if (configuration.getDatabaseId() != null) {
buildStatementFromContext(list, configuration.getDatabaseId());
}
// 解析 Statement
buildStatementFromContext(list, null);
}
//org.apache.ibatis.builder.xml.XMLMapperBuilder#buildStatementFromContext
private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
for (XNode context : list) {
// 用来解析增删改查标签的 XMLStatementBuilder
final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
try {
// 解析 Statement,添加 MappedStatement 对象
statementParser.parseStatementNode();
} catch (IncompleteElementException e) {
configuration.addIncompleteStatement(statementParser);
}
}
}
//org.apache.ibatis.builder.xml.XMLStatementBuilder#parseStatementNode
public void parseStatementNode() {
//获取id
String id = context.getStringAttribute("id");
//获取databaseId
String databaseId = context.getStringAttribute("databaseId");
if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
return;
}
String nodeName = context.getNode().getNodeName();
//获取sql类型
SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
//是否是查询语句
boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
//不是查询,要刷新缓存
boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect);
//是查询,要使用缓存
boolean useCache = context.getBooleanAttribute("useCache", isSelect);
//结果是否排序,默认否
boolean resultOrdered = context.getBooleanAttribute("resultOrdered", false);
// Include Fragments before parsing
XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);
includeParser.applyIncludes(context.getNode());
//参数类型
String parameterType = context.getStringAttribute("parameterType");
//解析参数类型
Class<?> parameterTypeClass = resolveClass(parameterType);
//语言
String lang = context.getStringAttribute("lang");
LanguageDriver langDriver = getLanguageDriver(lang);
// 解析selectkey,之后是用并删除
processSelectKeyNodes(id, parameterTypeClass, langDriver);
// 解析sql
KeyGenerator keyGenerator;
String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX;
keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true);
if (configuration.hasKeyGenerator(keyStatementId)) {
keyGenerator = configuration.getKeyGenerator(keyStatementId);
} else {
keyGenerator = context.getBooleanAttribute("useGeneratedKeys",
configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType))
? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
}
SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
//statement的类型,默认PreparedStatement
StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
Integer fetchSize = context.getIntAttribute("fetchSize");
Integer timeout = context.getIntAttribute("timeout");
String parameterMap = context.getStringAttribute("parameterMap");
String resultType = context.getStringAttribute("resultType");
Class<?> resultTypeClass = resolveClass(resultType);
String resultMap = context.getStringAttribute("resultMap");
String resultSetType = context.getStringAttribute("resultSetType");
ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);
if (resultSetTypeEnum == null) {
resultSetTypeEnum = configuration.getDefaultResultSetType();
}
//主键的名称
String keyProperty = context.getStringAttribute("keyProperty");
//主键的列名
String keyColumn = context.getStringAttribute("keyColumn");
String resultSets = context.getStringAttribute("resultSets");
// 创建 MappedStatement
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
resultSetTypeEnum, flushCache, useCache, resultOrdered,
keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}
//org.apache.ibatis.builder.MapperBuilderAssistant#addMappedStatement
public MappedStatement addMappedStatement(
String id,
SqlSource sqlSource,
StatementType statementType,
SqlCommandType sqlCommandType,
Integer fetchSize,
Integer timeout,
String parameterMap,
Class<?> parameterType,
String resultMap,
Class<?> resultType,
ResultSetType resultSetType,
boolean flushCache,
boolean useCache,
boolean resultOrdered,
KeyGenerator keyGenerator,
String keyProperty,
String keyColumn,
String databaseId,
LanguageDriver lang,
String resultSets) {
if (unresolvedCacheRef) {
throw new IncompleteElementException("Cache-ref not yet resolved");
}
id = applyCurrentNamespace(id, false);
//是否是查询语句
boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
//构建MappedStatement.Builder
MappedStatement.Builder statementBuilder = new MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType)
.resource(resource)
.fetchSize(fetchSize)
.timeout(timeout)
.statementType(statementType)
.keyGenerator(keyGenerator)
.keyProperty(keyProperty)
.keyColumn(keyColumn)
.databaseId(databaseId)
.lang(lang)
.resultOrdered(resultOrdered)
.resultSets(resultSets)
.resultMaps(getStatementResultMaps(resultMap, resultType, id))
.resultSetType(resultSetType)
.flushCacheRequired(valueOrDefault(flushCache, !isSelect))
.useCache(valueOrDefault(useCache, isSelect))
.cache(currentCache);
ParameterMap statementParameterMap = getStatementParameterMap(parameterMap, parameterType, id);
if (statementParameterMap != null) {
statementBuilder.parameterMap(statementParameterMap);
}
//构建MappedStatement
MappedStatement statement = statementBuilder.build();
// 在 Configuration 添加 MappedStatement
configuration.addMappedStatement(statement);
return statement;
}
//org.apache.ibatis.session.Configuration#addMappedStatement
//protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection")
.conflictMessageProducer((savedValue, targetValue) ->
". please check " + savedValue.getResource() + " and " + targetValue.getResource());
public void addMappedStatement(MappedStatement ms) {
mappedStatements.put(ms.getId(), ms);
}