Summary of Mybatis from source and architecture level @[TOC]
An overview of the
What is Mybatis?
Mybatis is a semi-automated persistence layer framework that encapsulates JDBC operations, supports customized SQL, and advanced mapping. But its database independence is low, two different databases, may need two sets of SQL statements
Basic use of Mybatis?
- Write a global configuration file
- Write mapper mapping files
- Load the configuration file and generate the SqlSessionFactory
- Create a SqlSession that invokes SQL statements in the MAPper mapping file to perform database operations
Architecture process
Three layer structure
The interface layer
The use of SqlSession and Mapper interface, to complete the call to SQL statements, daily development of the main contact with this layer
Data processing layer
This layer is the work of Mybatis, responsible for SQL statement assembly, query parameter binding, result set mapping
Foundation support
This layer can be understood as our global configuration. Including database connection information, transaction management information, configuration cache, write SQL statements in mapper mapping files, etc
The working process
- Pass the ID of the SQL statement, along with the query parameters, to the SqlSession
- Find the SQL information to execute and hand it to the Executor Executor
- Executor assembles and concatenates SQL statements for StatementHandler to handle
- StatementHandler encapsulates JDBC operations. It generates statements based on SQL information and uses ParameterHandler to parse and bind query parameters
- After StatemenHandler completes the query, the result set is sent to ResultSetHandler for result set information parsing and encapsulation processing (parameter parsing, result set parsing, both use TypeHandler to do type conversion, Java type and JDBC type).
The source code section
Global configuration file parsing process
- Get the InputStream of the configuration file and create the Document object
- Each configuration node is parsed using Xpath syntax
- Encapsulate the information in a Configuration object to generate the SqlSessionFactory
Source process
SqlSessionFactoryBuilder # build
|- XMLConfigBuilder # parse
|- XMLConfigBuilder # parseConfiguration
Copy the code
Mapper Map file parsing process
- A mapper. XML mapping file, uniquely identified by the namespace attribute
- The mapper. XML mapping file with the namespace attribute is registered with mapperRegistry in the Configuration for subsequent generation of Mapper proxy objects
- A mapper. XML corresponds to a MapperBuilderAssistant object. The builderAssistant object parses and stores the public tags in the mapper. XML, such as parameterMap, resultMap, Cache, SQL, These tags may be used in a CRUD tag
- Parsing CRUD label, that is, the select | update | insert | delete tags, a CRUD label, is encapsulated into a MappedStatement object, to label the id attribute as a unique identifier, MappedStatement contains SQL statement information, parameter mapping information, and result set mapping information
Source process
XMLConfigBuilder # mapperElement
|- XMLMapperBuilder # parse
|- XMLMapperBuilder # configurationElement
Copy the code
SQL loading and assembly process
SQL loading
- SQL statements are parsed and encapsulated when parsing CRUD tags in mapper mapping files
- Encapsulate a CRUD tag into a SqlNode, and encapsulate its child elements (which may be text nodes or dynamic SQL nodes) into a SqlNode. Use the combination mode to assemble these SQLNodes, and finally encapsulate SqlNode and Configuration together. The formation of SqlSource
- Those with dynamic SQL tags, or those with ${}, are encapsulated as DynamicSqlSource, and the rest are encapsulated as RawSqlSource (which is parsed and encapsulated as StaticSqlSource when Executor executes).
- The SqlSource, along with other information, is encapsulated as a MapperStatement, a CRUD tag that corresponds to an MappedStatement
Source process
XMLMapperBuilder # buildStatementFromContext
|- XMLStatementBuilder # parseStatementNode
|- XMLLanguageDriver # createSqlSource
|- XMLScriptBuilder # parseScriptNode
Copy the code
SQL assembly
- When the Executor is called for execution, the corresponding MappedStatement is looked up and its SqlSource getBoundSql is called to assemble the SQL statement and encapsulate the query parameters
- When the getBoundSql method is called, SqlNode’s apply method is called. Different SqlNode subclasses parse dynamic SQL tags, concatenate SQL statements, and replace #{} with? ${} will be used to concatenate the string and encapsulate it into the StaticSqlSource. The StaticSqlSource will contain the SQL statement and query parameters
Source process
CachingExecutor # query
|- MappedStatement # getBoundSql
|- DynamicSqlSource # getBoundSql
|- SqlNode # apply // Dynamic SQL assembly, and string concatenation ${}
|- SqlSourceBuilder # parse // Replace #{} with?
// encapsulate the StaticSqlSource
// And call getBoundSql for StaticSqlSource
//new a new BoundSql, passing in the assembled SQL statement and the query parameters
Copy the code
Execute the query procedure
- Extract an MappedStatement based on the ID from the Configuration
- Leave the MappedStatement to Executor
- The Executor calls getBoundSql in MappedStatement to get the assembled SQL statement and query parameters
- Create a StatementHandler based on the query parameters, MappedStatement, and other information
- StatementHandler creates a Statement object and uses ParameterHandler to bind the Statement as an input parameter
- Execute the query and submit the result set to a ResultSetHandler
Source process
DefaultSqlSession # selectList |- CachingExecutor # query |- BaseExecutor # query |- BaseExecutor # queryFromDatabase |- SimpleExecutor # doQuery |- Configuration # newStatementHandler |- SimpleExecutor # prepareStatement |- StatementHandler # queryCopy the code
Cache processes
- CachingExecutor checks whether level-2 cache is enabled. If level-2 cache is enabled, the cache accesses level-2 cache data
- If level 2 cache is not enabled, or level 2 cache fails, BaseExecutor will attempt to fetch data from level 1 cache. If level 1 cache is not available, the database will be accessed
- Level 2 cache is mapper level, that is, a mapper, corresponding to a level 2 cache. In the source code, the secondary cache is held by MappedStatement. Level 2 caching is through mapper mapping files
<cache/>
Label open - Level 1 caching cannot be turned off, but can be set in global configuration
<setting name="localCacheScope" value="STATEMENT"/>
Invalidate it (clears level 1 cache every time an operation is executed)
Source process
// Level 2 cache
CachingExecutor # query
|- MappedStatement # getCache// Get the level 2 cache under the mapper
|- TransactionalCacheManager # getObject // Find if there is data in the cache
|- TransactionalCache # getObject // Find if there is data in the cache
|-TransactionalCacheManager # putObject // Store level 2 cache
|- TransactionalCache # getObject
// If the level-2 cache is not matched, go to level-2 cache
BaseExecutor # query
|- PerpetualCache # getObject // Fetch data from level 1 cache
Copy the code
Lazy loading process
- After the query ends, when the ResultSetHandler is called to process the result set, if lazy loading is enabled and there are nested queries, a proxy object will be generated for the result
- When the get method of the result is invoked to access the lazy-loaded data and the data is found to be empty, the MappedStatement is obtained and the query result is set to the main object
Source process
DefaultResultSetHandler # createResultObject
|- Configuration # getProxyFactory
|- JavassistProxyFactory # createProxy
// JavassistProxyFactory is used by default
Copy the code
The process of obtaining a Mapper proxy
- Calling mapperRegistry in Configuration to find the class information for this Mapper will find a MapperProxyFactory object
- Using the JDK’s built-in dynamic Proxy, call Proxy under java.lang.Reflect to generate a Proxy class
Source process
# # DefaultSqlSession getMapper | - MapperRegistry getMapper | - MapperProxyFactory # newInstance | - MapperProxy # constructor | - Proxy.newProxyInstanceCopy the code
Mybatis plug-in process
The myBatis plugin works with the following classes
- Executor
- StatementHandler
- ParameterHandler
- ResultSetHandler
Interceptor interface, overwrite intercept method, intercept method in the completion of plug-in interception logic. The plugin method is overridden by calling plugin.wrap in the plugin method to generate a proxy object and return it. The underlying JDK dynamic proxy is also used
Source process
// Take Executor as an example
DefaultSqlSessionFactory # openSession
|- Configuration # newExecutor
|- InterceptorChain # pluginAll
Copy the code
Summary of class relation
Configuration file parsing is related
-
BaseBuilder
-
XMLConfigBuilder
-
XMLMapperBuilder
Hold a MapperBuilderAssistant
-
XMLStatementBuilder
-
XMLScriptBuilder
-
SQL assembly correlation
-
SqlSource
-
DynamicSqlSource :
Contains dynamic SQL, or ${}, which is parsed into this class
-
RawSqlSource :
Non-dynamic SQL, and ${}, will be parsed into this class
-
StaticSqlSource
When Executor executes the query and calls the getBoundSql method, it assembles the SQL statement and wraps it with the query parameters for this class
-
-
SqlNode
-
TextSqlNode
Text node
-
StaticTextSqlNode
Text node, and the text does not contain ${}
-
IfSqlNode
-
ForEachSqlNode
-
ChooseSqlNode
-
TrimSqlNode
There are two subclasses, namely
- WhereSqlNode
- SetSqlNode
-
MixedSqlNode
As the root node, it has a List
field
-
Perform related
-
Executor
-
BaseExecutor
It has 3 subclasses, respectively
- SimpleExecutor
- ReuseExecutor
- BatchExecutor
-
CachingExecutor
-
-
StatementHandler
-
RoutingStatementHandler
It is used for route selection only
-
BaseStatementHandler
It has 3 subclasses, respectively
- SimpleStatementHandler
- PreparedStatementHandler
- CallableStatementHandler
-
-
ParameterHandler
-
ResultSetHandler
-
Cache
- PerpetualCache
- LruCache
- FifoCache
- SerializedCache
- LoggingCache
- SynchronizedCache
- SoftCache
- WeakCache
- TransactionalCache
Design patterns
The various Builders are the Builder pattern
SqlSessionFactory is the factory mode
BaseExecutor contains a hook method doQuery, which is a template method pattern
The CachingExecutor and second-level Cache Cache architectures are decorator patterns
The Mapper proxy object, as well as lazy loading, is the proxy mode
SqlNode is a composite system
ErrorContext records the ErrorContext in each thread, using a ThreadLocal implementation and a singleton pattern