1. Overall functional architecture of MyBatis
Mybatis is mainly divided into three layers, from top to bottom: interface layer, data processing layer, and basic support layer. The architecture diagram is as follows:
2. Introduction of myBatis four core JDBC components
Mybatis built-in core 4 functional components, respectively are Executor, StatementHandler, ParameterHandler, ResultSetHandler, function description is as follows:
Component name | Component description |
---|---|
Executor | The framework’s core scheduler executor component, which is used for generating SQL statements and cache maintenance, has two implementations: BaseExecutor and CachingExecutor |
StatementHandler | To encapsulate JDBC statement operations, set parameters, and map results. The main implementation is BaseStatementHandler, CallableStatementHandler, PreparedStatementHandler, SimpleStatementHanlder, RoutingStatementHandl Er. |
ParameterHandler | This is used to map the parameters passed in to the parameters required by the statement |
ResultSetHandler | It is mainly used to map JDBC returned results to specific List collection, and complete the transformation from database type to program entity class. The default implementation is DefaultResultSethandler |
3. Workflow diagram of MyBatis Mapper agent
Mybatis core class description
The name of the class | Class description |
---|---|
SqlSessionFactoryBuilder | SqlSessionFactory constructor, the builder pattern, uses the build method to build from InputStream, Reader, and so on |
SqlSessionFactory | SqlSession factory class, used to create SQLSessions, passing the Configuration parameter |
SqlSession | SqlSession code An SQL execution session that carries global configuration information |
Configuration | Mybatis global configuration management object, including all myBatis configuration information, including data source and all XML file information |
MappedStatement | And an insert | update | delete | select tags corresponding object, segments of a SQL statement used to store information |
SqlSource | It is used to generate final executable SQL statements for different types of SQL statements. The main implementations are DynamicSqlSource, RawSqlSource, StaticSqlSource, and MixedSqlSource |
BoundSql | It is used to bind and store SQL statement fragments and parameters, carrying SQL statement and parameter information |
TypeHandler | Used to complete the conversion between Java types and JDBC data types |
XMLConfigBuilder | It resolves global Configuration information, such as environment and dataSource information, and encapsulates the information into the Configuration |
XMLMapperBuilder | Is mainly used to parse the XML document in the select | insert | update | delete tags, and encapsulated into MappedStatement stored in the Configuration |
XMLScriptBuilder | It is mainly used to parse the dynamic tags and dynamic SQL statements in SQL statements. After parsing and parameter mapping, it finally constructs a StaticSqlSource to output and save a complete SQL statement that can be executed |
XPathParser | It is mainly used to parse configuration files and form Document objects that can be operated based on dom |
ParameterMapping | An object used to hold mappings between dynamic parameter names and parameter values in SQL |
5, MyBatis configuration initialization part of the core source code
5.1 Analysis of program code entry:SqlSessionFactoryBuilder#build
The SqlSessionFactoryBuilder is: used to initialize the SqlSessionFactory, default DefaultSqlSessionFactory implementation
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
// XMLConfigBuilder: used to parse XML configuration files
// Use the Builder pattern
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
// Parser.parse () : Parse the XML Configuration file using XPATH and encapsulate the Configuration file into a Configuration object
// Return the DefaultSqlSessionFactory object, which has the Configuration object (encapsulating Configuration file information).
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.}}}public SqlSessionFactory build(Configuration config) {
// Create a default implementation class for the SqlSessionFactory interface
return new DefaultSqlSessionFactory(config);
}
Copy the code
5.2. Parse global Configuration information:XMLConfigBuilder#parse
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
/** * Parse the XML configuration file *@return* /
public Configuration parse(a) {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
// Parser.evalNode ("/configuration") : Parse the configuration root node using the XPATH parser
// Start parsing from the configuration root node and encapsulate the parsed content into the Configuration object
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
private void parseConfiguration(XNode root) {
try {
//issue #117 read properties first
// Parse the tag
propertiesElement(root.evalNode("properties"));
// Parse the
tag
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
loadCustomLogImpl(settings);
// Parse the tag
typeAliasesElement(root.evalNode("typeAliases")); . . .// Parse the tag
environmentsElement(root.evalNode("environments"));
// Parse the tag
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
// Resolve the tag
typeHandlerElement(root.evalNode("typeHandlers"));
// Parse the tag
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: "+ e, e); }}Copy the code
6, mybatis mapper file load part of the core source code
**: **XMLConfigBuilder#mapperElement->XMLMapperBuilder#parse
InputStream inputStream = Resources.getUrlAsStream(url);
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
// Parse the mapper mapping file with XMLMapperBuilder
mapperParser.parse();
public void parse(a) {
// Mapper Whether the mapping file has been loaded
if(! configuration.isResourceLoaded(resource)) {// Start parsing from the
root tag in the mapping file until the complete parsing is complete
configurationElement(parser.evalNode("/mapper"));
// The tag is parsed
configuration.addLoadedResource(resource);
bindMapperForNamespace();
}
parsePendingResultMaps();
parsePendingCacheRefs();
parsePendingStatements();
}
/** * Parse the mapping file *@paramContext maps XNode */ corresponding to the root node of the file <mapper>
private void configurationElement(XNode context) {
try {
// Get the namespace value of the
tag
String namespace = context.getStringAttribute("namespace"); . . .// Parse the
subtag
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
// Parse the
subtag
resultMapElements(context.evalNodes("/mapper/resultMap"));
// Parse the < SQL > child tag, which is the SQL fragment
sqlElement(context.evalNodes("/mapper/sql"));
// Parse the
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); }}Copy the code
6.2 analytical MappedStatement: XMLMapperBuilder#buildStatementFromContext
private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
for (XNode context : list) {
// MappedStatement parser
final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
try {
// Create an MappedStatement by parsing the four labels, including select
statementParser.parseStatementNode();
} catch (IncompleteElementException e) {
configuration.addIncompleteStatement(statementParser);
}
}
}
MapperBuilderAssistant#addMappedStatement
// Use the Builder pattern to create the MappedStatement.Builder, which is used to create the MappedStatement object
MappedStatement.Builder statementBuilder = newMappedStatement.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);
}
// Create an MappedStatement using mappedStatement. Builder
MappedStatement statement = statementBuilder.build();
// Store the MappedStatement object in the Map set in the Configuration. The key is the statement ID and the value is the MappedStatement object
configuration.addMappedStatement(statement);
Copy the code
6.3 processing SqlSource: XMLStatementBuilder#parseStatementNode->langDriver.createSqlSource
// Parse the SQL (pre: <selectKey> and <include> were parsed and removed)
// Create SqlSource, parse SQL, encapsulate SQL statement (no parameter binding) and input parameter information
SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
XMLLanguageDriver#createSqlSource
public SqlSource createSqlSource(Configuration configuration, XNode script, Class
parameterType) {
// The dynamic SQL tag handler is initialized
XMLScriptBuilder builder = new XMLScriptBuilder(configuration, script, parameterType);
// Parse dynamic SQL
return builder.parseScriptNode();
}
public SqlSource parseScriptNode(a) {
// Parse the SQL statement in the select/INSERT/Update/delete tag, and finally encapsulate the parsed SqlNode into the List set in the MixedSqlNode
// **** encapsulates the SQL information with the ${} number into TextSqlNode
// **** encapsulate SQL information with #{} number to StaticTextSqlNode
// **** Encapsulate the SQL information in the dynamic SQL tag into different SQLNodes
MixedSqlNode rootSqlNode = parseDynamicTags(context);
SqlSource sqlSource = null;
// If SQL contains ${} and dynamic SQL statements, wrap SqlNode into DynamicSqlSource
if (isDynamic) {
sqlSource = new DynamicSqlSource(configuration, rootSqlNode);
} else {
// If SQL contains #{}, encapsulate SqlNode into RawSqlSource and specify parameterType
sqlSource = new RawSqlSource(configuration, rootSqlNode, parameterType);
}
return sqlSource;
}
Copy the code