Cover: Luo Xiaoxi
Author: Pan Pan
The pandemic of 2020 will tear the world to pieces.
Today, people are still nervous.
I’m glad to be in this safe country,
Get a regular job at the same time.
,
East often speak a word: late autumn mentality.
When the general trend, do not follow, heckling,
In times of depression, do not give up the confidence to sow and till,
Do not dry when hot, do not abandon when cold,
This is the late autumn mentality.
,
The pandemic, I believe, is just the law of nature,
It is also the time when we keep the mentality of late autumn,
Sow and till in silence,
This year, the world will slowly recover, hope will come.
In 2021, we should be confident ヾ(◍°∇°◍) Blue ゙
It’s gonna be full of stuff
The above picture can be saved as a circle of friends cover picture ~
preface
Last section we introduced “Mybatis series full solution (5) : the whole net most complete! Detailed explanation of Mybatis Mapper mapping file”, through this article, we can basically master the basic usage and the skills of Mapper nine top elements. In this section, we start to go deeper. I have selected several core apis in Mybatis framework to discuss with you and consolidate these apis, which will help you learn and understand the whole Mybatis framework, especially the core data processing layer of Mybatis. You will definitely form a clear set of veins. In short, I hope everyone can become Mybatis King!
In addition, our Mybatis full solution series has been updated
Mybaits Series full solutions (continuously updated)
- Mybatis series full solution (a) : handwriting a set of persistent layer frame
- Mybatis series full solution (2) : Mybatis introduction and environment construction
- Mybatis series full solution (3) : Mybatis simple CRUD use introduction
- Mybatis series full solution (four) : the most complete network! Mybatis configuration file XML overview
- Mybatis series full solution (5) : the most complete network! Mybatis Mapper mapping file
- Mybatis series full solution (6) : Mybatis most core API you know how many?
- Mybatis series full solution (7) : Dao layer two ways to achieve
- Mybatis series full solution (8) : Mybatis dynamic SQL
- Mybatis series full solution (9) : Complex mapping of Mybatis
- Mybatis series full solution (10) : Mybatis annotation development
- Mybatis series full solution (11) : Mybatis cache full solution
- Mybatis plug-in development
- Mybatis series full solution (13) : Mybatis code generator
- Spring integrates Mybatis
- Mybatis series full solution (15) : SpringBoot integrated Mybatis
- Mybatis series full solution (16) : Mybatis source code analysis
This article directory
1. Mybatis architecture and core API
2. Configuration — Global Configuration object
3. Resources — Resource helper class
SqlSessionFactoryBuilder — SessionFactoryBuilder
SqlSessionFactory — Session factory
SqlSession — session
Executor — Executor
StatementHandler — StatementHandler
ParamerHandler — Parameter handler
10. ResultSetHandler — ResultSetHandler
TypeHandler — type converter
12. MappedStatement — Statement object
SqlSource — SQL source
BoundSql — SQL statement
1. Mybatis architecture and core API
If not, in the subsequent source code analysis related articles, we will carry out a sweep of the source code of Mybatis, mining every point worth our in-depth understanding/memory knowledge points. In this article, we will first spread out the architecture/hierarchy of Mybatis, looking at the overall design of Mybatis architecture, and then digest several core apis in detail.
The overall sequence of context, I hope to make you look forward to ~
Let’s take a look at Mybatis source code,
Take a look at the Ta directory structure:
Look, Mybatis source code package neatly row in org.apache.ibatis directory, the basic design purpose OF my simple carpeted into the above picture, easy for everyone to intuitive understanding, of course, only look at the source code package directory structure, it will be boring, so let’s have a look, In fact, Mybatis source package function can be so divided:
The figure above gives us an abstract understanding of Mybatis architecture.
However, in fact, the specific division of functions, core API scenario application, what will be a set of process presentation?
Take a look at the functional architecture design below, perhaps you can understand better.
According to the functional architecture of Mybatis, we can divide it into three layers:
-
Interface layer: This layer provides a series of interfaces for users to directly participate in the use, including information configuration and actual data manipulation calls. The configuration mode includes XML configuration mode and Java API configuration mode. Users can also initiate requests for adding, deleting, modifying, and checking the database through the API of the interface layer. The interface of the interface layer will deliver the received call requests to the components of the data processing layer for processing.
-
Data processing layer: this layer is the core layer of Mybatis and is responsible for data processing, including SQL parameter mapping analysis, actual execution of SQL statements, mapping processing of execution result sets, etc.
-
Framework support layer: this layer belongs to the logistics support layer of Mybatis, including database connection management, transaction control management, configuration loading and cache processing, log processing, exception processing, etc., to provide basic support ability and guarantee the data processing of the upper layer.
As we know, Mybatis framework allows users to only provide configuration information and focus on THE writing of SQL. Users do not need to worry about and participate in connection management database/transaction, or actual SQL parameter mapping/statement execution/result set mapping and other operations.
However, we are curious to know how the data processing of the core part of Mybatis supports user requests in the overall process. At the same time each component interaction, and how to flow?
As it happens, I have a picture here that shows the whole process:
Explain according to the above frame flow chart:
- Create the configuration and call the API: The first step is to create the core Configuration file configuration. XML and the mapping file mapper. XML (you can also create the above two configurations through annotations), and prepare the basic Configuration and SQL statements. The second step is to directly call the database operation interface in Mybatis framework.
- Load configuration and initialize: Mybatis framework will read the configuration file as input stream according to the content of the core configuration file and SQL mapping file provided by the application side using the resource auxiliary class Resources. The object is then parsed and encapsulated into the Configuration object and MappedStatement object by the corresponding parser, and finally stored in memory.
- Create a session and receive a request: After the Mybatis framework loads the configuration and initializes the configuration object, the SessionFactoryBuilder SqlSessionFactory also creates the session factory SqlSessionFactory, which creates the session SqlSession based on the application request. For database interaction on the application side.
- Processing requests: SqlSession receives the request and does not actually process it. Instead, it forwards the request to the Executor, which dispatches to the StatementHandler StatementHandler, which combines with the ParameterHandler, Perform database operations (underlying encapsulates JDBC Statement operations).
- Return processing results: after each StatementHandler StatementHandler has processed the database operation, it works with the ResultSetHandler and the TypeHandler to map and encapsulate the result set returned by the underlying JDBC, and finally return the encapsulated object.
For each of the core apis involved in the overall framework flow above, we will take a look at them one by one, but will not break down the source code and principles, including construction details, as we will do in the following source code anatomy sections.
2. Configuration — Global Configuration object
For Mybatis global Configuration object Configuration, I believe that both beginners and experienced players, will not be unfamiliar. The entire Mybatis universe revolves around Configuration. The Configuration object has almost the same structure as the config. XML Configuration file, covering properties, Settings, typeAliases, typeHandlers, ObjectFactory (objectFactory), mappers (mapper), objectFactory (objectFactory), mappers (mapper), objectFactory (objectFactory) Mybatis configuration file XML overview of a detailed taste of it.
The Configuration object Configuration is parsed by the XMLConfigBuilder, and the Configuration information in the global Configuration file config. XML and mapper. XML is constructed into a complete Configuration object. We will analyze the whole process in detail in the subsequent source code analysis.
3. Resources — Resource helper class
As we know, Configuration information such as Configuration and Mapper is stored in XML files. When Mybatis framework constructs Configuration objects, it must first load XML file information into streams and then perform subsequent parsing and encapsulation. Resources are the auxiliary class of Resources. That’s exactly what you do. Whether you load a local resource or a remote resource, you end up accessing the resource file and output the file stream through the class loader.
// Load the core configuration file
InputStream resourceAsStream =
Resources.getResourceAsStream("Config.xml");
Copy the code
Resources actually provides a number of methods to solve your file loading problem in no time:
SqlSessionFactoryBuilder — SessionFactoryBuilder
SqlSessionFactoryBuilder is a session factory builder in Mybatis. After the resource helper class Resources reads the file stream information, It is responsible for parsing file flow information and building the session factory SqlSessionFactory. (Parsed Configuration files include: global Configuration and Mapper)
On the application side, we typically build the session factory directly using SqlSessionFactoryBuilder:
// Get the sqlSession factory object
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(resourceAsStream);
Copy the code
Of course, if you integrate projects with the Spring framework, you don’t need to build the session factory yourself. You can specify it in the Spring configuration file. For example, specify a bean object with the id sqlSessionFactory, The class class designated as org. Mybatis. Spring. SqlSessionFactoryBean.
SqlSessionFactoryBuilder internally parses the file stream through the parser XMLConfigBuilder, encapsulates it into a Configuration object, and passes the Configuration object to build an instance.
public SqlSessionFactory build( InputStream inputStream, String environment, Properties properties) {
// Configure parser parsing
XMLConfigBuilder parser =
new XMLConfigBuilder(
inputStream,environment, properties);
// Final instance session factory
return build(parser.parse());
}
Copy the code
Mybatis default implementation is a new instance of DefaultSqlSessionFactory.
// Final instance session factory
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
Copy the code
The SessionFactoryBuilder SqlSessionFactoryBuilder applies the Builder pattern to build SqlSessionFactory objects for subsequent production of SqlSession objects. This constructor is basically a portal builder for the Mybatis framework. It provides a series of polymorphic methods called Build () that allow users to build instances of the session factory SqlSessionFactory using XML configuration files or Java API (Properties).
The lifetime of SqlSessionFactoryBuilder is only for SqlSessionFactory. Once SqlSessionFactory is instantiated, SqlSessionFactoryBuilder will die and be discarded.
So the best scope for SqlSessionFactoryBuilder instances is the method scope (that is, local method variables). You can reuse SqlSessionFactoryBuilder to create multiple instances of SqlSessionFactory, but it’s best not to keep it around all the time to ensure that all XML parsing resources can be freed up for more important things.
A set of interfaces to flexibly build session factories in SqlSessionFactoryBuilder:
SqlSessionFactory — Session factory
SessionFactory SqlSessionFactory is an interface that produces the database session object SqlSession. It has two implementation classes:
- DefaultSqlSessionFactory (default implementation)
- SqlSessionManager (deprecated, implements only one more Sqlsession interface)
In introducing the SessionFactory builder SqlSessionFactoryBuilder, we learned that the builder creates an instance of DefaultSqlSessionFactory by default, and that the session factory itself binds an important property, the Configuration object. During production sessions, the Configuration Configuration object is eventually passed and set to session SqlSession.
Session factories can simply create SqlSession instances:
// Create an SqlSession instance
SqlSession session = sqlSessionFactory.openSession();
Copy the code
Session factory create SqlSession, binding data sources, transaction processing, actuators, etc., the default session factory implementation class DefaultSqlSessionFactory, when creating the session object will eventually call openSessionFromDataSource method, This is how it is achieved:
// Every openSession will eventually call this
private SqlSession openSessionFromDataSource(
ExecutorType execType,
TransactionIsolationLevel level,
boolean autoCommit) {
// Environment configuration
final Environment environment =
configuration.getEnvironment();
// Transaction factory
final TransactionFactory transactionFactory =
getTransactionFactoryFromEnvironment(environment);
/ / transaction
Transaction tx =
transactionFactory.newTransaction(
environment.getDataSource(),
level,
autoCommit);
/ / actuator
final Executor executor =
configuration.newExecutor(tx, execType);
// Finally generate the session
return new DefaultSqlSession(
configuration, executor, autoCommit);
}
Copy the code
In addition, session factories actually provide a set of interfaces to flexibly produce session SQLSessions. You can specify:
- Transaction handling: Do you want to use/enable transaction scoping in the Session scope (that is, not commit transactions automatically) or use auto-commit. SqlSession does not commit transactions by default, and you need to commit transactions manually for add, delete, or change operations.
- Database Connection: Do you want MyBatis to help you get a Connection from a configured data source, or do you want MyBatis to help you get a Connection from a configured data source?
- Executor type: You want to specify what type of executor you want to use to create/execute/preprocess statements. It can be a SimpleExecutor, a ReuserExecutor, a BatchExecutor, etc., as described below.
- Transaction isolation levels support: Support for five JDBC isolation levels (NONE, READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, and SERIALIZABLE). For transaction related content, we will cover in detail in the following Spring Series full Solutions. Transaction isolation levels are used to solve problems such as dirty reads, unrepeatable reads, and phantom reads. Using different transaction isolation levels will inevitably lead to different database execution efficiencies, so we have different requirements for isolation levels in different systems/functions.
Once created, the SqlSessionFactory should persist for the duration of the application, and there is no reason to discard it or recreate another instance. The best practice with SqlSessionFactory is not to create the SqlSessionFactory more than once while the application is running. Rebuilding SqlSessionFactory more than once is considered a code “bad habit.” So the best scope for SqlSessionFactory is the application scope. The simplest is to use a singleton or a static singleton.
Remember, create SqlSessionFactory once!
Each database corresponds to an instance of SqlSessionFactory. Once created, the SqlSessionFactory should have the same life cycle as the application. So, if you want to connect to two databases, create two SqlSessionFactory instances, one for each database; With three databases, you need three instances, and so on.
SqlSession — session
SqlSession is an interface with two implementation classes:
- DefaultSqlSession (default implementation)
- SqlSessionManager (deprecated)
The default DefaultSqlSession instance provides so many methods for users to use, more than 30 of them:
In addition to CURD, It also provides control of transactions such as commit/close/rollback, fetching of configuration objects such as getConfiguration(), updating the execution of batch statements such as flushStatements(), cache clearing such as clearCache(), and the use of mapper GetMapper () and so on.
For the client application level, familiar with THE sqlSession API basic can be arbitrary operation database, but we want to further understand the sqlSession internal how to execute SQL? SqlSession is a top-level class in Mybatis that is used to interact with the database. It is usually bound to the local thread ThreadLocal. A session uses one sqlSession and is closed after being used.
SqlSession is called the top-level class for data interaction because it does no actual database operations. SqlSession operations on the database will be forwarded to a specific Executor. The Executor is then assigned to the StatementHandler StatementHandler, which in combination with the ParameterHandler ParameterHandler, Do the final database execution processing together (again, encapsulating the JDBC Statement operation underneath). After each statement processor StatementHandler completes the database operation, the result junction processor ResultSetHandler and type processor TypeHandler are used to map and encapsulate the result set returned by the underlying JDBC. The expected wrapped object is eventually returned.
Note the red highlight of sqlSession in the following illustration, which details the actual execution path of the session:
SqlSession can be a database session, a session can be executed once, or you can batch execute multiple times, but once the session is closed, you must re-create the session to execute SQL again.
Each thread should have its own SqlSession instance. SqlSession instances are not thread-safe and therefore cannot be shared, so their best scope is the request or method scope. A reference to an SqlSession instance must never be placed in a static domain of a class, or even an instance variable of a class. A reference to an SqlSession instance should also never be placed in any type of managed scope, such as HttpSession in the Servlet framework. If you are currently using a Web framework, consider putting SqlSession in a scope similar to HTTP requests. In other words, each time an HTTP request is received, an SqlSession can be opened, and when a response is returned, it can be closed. The close operation is important, and to ensure that the close operation is performed every time, you should put the close operation ina finally block.
After Spring integrates with Mybatis, it is possible to create thread-safe, transaction-based SQLSessions and manage their life cycle through dependency injection.
Executor — Executor
Executor is an Executor interface, which is the scheduling core of Mybatis. It defines a set of methods for managing Statement objects and fetching transactions, and is responsible for generating SQL statements and maintaining level 1 / level 2 query cache. SqlSessionFactory Creates an executor when creating an SqlSession and specifies the executor type. SimpleExecutor is used by default. The executor interface has five descendant implementation classes, of which BaseExecutor is an abstract class. The other four descendant implementation classes are SimpleExecutor, BatchExecutor, ReuseExecutor, and CachingExecutor.
-
BaseExecutor: An abstract class that implements the basic Executor interface and provides basic support for the next-level implementation of class executors. BaseExecutor has three subclasses: SimpleExecutor, ResuseExecutor, and BatchExecutor.
-
SimpleExecutor: A common executor that inherits the BaseExecutor abstract class and is the default executor used in MyBatis. Each time you perform an update or SELECT operation, you open a Statement object and close it immediately. (It can be a Statement or a PrepareStatement object).
-
ReuseExecutor: a multiplexer that inherits the BaseExecutor abstract class. In this case, the multiplexer refers to the repeated use of Statement. Each time a Statement is executed, it checks to see if there is a Statement object based on the SQL cache. If the Connection for a previously cached Statement object is not closed, the existing Statement object will continue to be used. Otherwise, a new Statement object will be created and cached. Since every new SqlSession has a new Executor object, the Statement cached on ReuseExecutor is scoped to the same SqlSession.
-
BatchExecutor: BatchExecutor. It inherits the BaseExecutor abstract class to improve performance through batch operations. It is used to transport multiple SQL statements to the database for execution at once. Since there is an internal implementation of the cache, we need to call flushStatements() to flush the cache after use.
-
CachingExecutor: Cache Executor, which inherits the BaseExecutor abstract class and adds the functions of a secondary cache to Executor objects. CachingExecutor has an important attribute delegate, which is the delegate Executor object. The value can be any of SimpleExecutor, ReuseExecutor, or BatchExecutor. When CachingExecutor performs a database update operation, it directly calls the update method of the delegate object. When a query is executed, it retrieves the result from the cache, returns it if it exists, or delegates it to the database if it does not exist, and stores it in the cache cache.
Mybatis builds the Configuration class with executortype. SIMPLE as the ExecutorType by default. When our session factory DefaultSqlSessionFactory starts producing SqlSession sessions, In this case, specific actuators will be instantiated according to the type of actuators specified during Configuration class construction. The process is as follows:
// 1. Configuration During class construction
// Specifies that the default actuator type is common actuator
protected ExecutorType defaultExecutorType
= ExecutorType.SIMPLE;
// 2. Configuration In the Configuration class
// Provide methods to get the default actuator type
public ExecutorType getDefaultExecutorType(a) {
return defaultExecutorType;
}
// session factory creates an INSTANCE of SqlSession
SqlSession session = sqlSessionFactory.openSession();
// 4. OpenSession actual logic
public SqlSession openSession(a) {
return
openSessionFromDataSource(
// Get the default actuator
configuration.getDefaultExecutorType(),
null.false
);
}
Copy the code
Now, I’m sure some of you are wondering, can we specify other actuators?
The answer is: sure, there are two ways to specify:
-
The first method is specified through the Java API when openSession is opened. Such as:
// Create an SqlSession instance
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.REUSE)
ExecutorType is an enumeration
// SIMPLE, REUSE, BATCH
Copy the code
- The other option is to specify the default actuator type through Configuration. For example,
<settings>
<! -- SIMPLE, REUSE, BATCH -->
<setting name="defaultExecutorType" value="REUSE"/>
</settings>
Copy the code
Mybatis (Mybatis, Mybatis, Mybatis, Mybatis, Mybatis, Mybatis) Basically, these attributes are provided by Mybatis for us to set flexibly. Even if we do not set Mybatis, there will be default values. For example, the default value of defaultExecutorType is SIMPLE. If you look at Mybatis’ default build when parsing the Configuration, you’ll see:
Parsers that parse Configuration (code paths for classes and concrete methods) :
org.apache.ibatis.builder.xml.XMLConfigBuilder#settingsElement
Here is what sets the defaultExecutorType attribute defaultExecutorType:
// Config file resolver
public class XMLConfigBuilder {
// Finally parsed Configuration object
protected final Configuration configuration;
// Set the properties for the Configuration object
private void settingsElement(Properties props) {
// Set the default actuator type, which is SIMPLE
configuration.setDefaultExecutorType(
ExecutorType.valueOf(
props.getProperty(
"defaultExecutorType"."SIMPLE")));
/ /... And of course there's a lot of property Settings
/ /... As long as you configure it in < Settings >}}Copy the code
Note that you can specify actuator types based on business needs, such as SIMPLE (common actuator), REUSE (REUSE actuator), and BATCH (BATCH actuator).
The cache executor cache executor cache executor cache executor
That’s true, because the cache executor and the other three are not quite the same, CachingExecutor is going to have to have a level 2 cache on, so don’t think about what level 1 cache is, what level 2 cache is, and we’ll talk about caching in more detail in a future article.
We first understand a concept can be, is Mybatis level cache is opened by default, no matter you want it or not, there will be level cache, and level cache, is closed by default, but allow us to manually open.
Compare the difference between the executor execution before and after enabling the level 2 cache.
- If level 2 cache is not enabled, the actuator executes:
- When level 2 caching is enabled, the actuator executes:
The Executor interface provides the following overloaded methods for transaction/cache/database management and access:
At this point, we have a basic understanding of the executor, but in fact, we know that the executor itself does not execute the SQL statement. Instead, it dispatchers to the statement processor StatementHandler, which in combination with the ParameterHandler, ParameterHandler, ultimately performs database operations.
StatementHandler — StatementHandler
StatementHandler is a Statement processor interface that encapsulates JDBC Statement operations. StatementHandler is responsible for JDBC Statement operations, such as setting parameters and mapping result sets. StatementHandler is an interface that interacts with the database. StatementHandler statement processor instance, which is built while the executor is actually performing CRUD operations, PrepareStatementHandler is used by default. The statement processor interface has five descendant implementation classes, of which BaseStatementHandler is abstract. The other four descendant implementation classes are: SimpleStatementHandler, PrepareStatementHandler, CallableStatementHandler, RoutingStatementHandler.
-
BaseStatementHandler: Basic statement processor (abstract class), which basically implements the core parts of statement processor interface, including configuration binding, executor binding, mapper binding, parameter processor construction, result set processor construction, statement timeout setting, statement closing, etc. In addition, new methods called instantiateStatement are defined for different subclasses to implement to get different types of statement connections. Subclasses can execute plain SQL statements, precompiled executions, stored procedures, etc.
-
SimpleStatementHandler: BaseStatementHandler abstract class, corresponding to the java.SQL.Statement object processing, processing ordinary SQL without dynamic parameters, that is, to execute simple concatenated string statements. SimpleStatementHandler needs to compile SQL every time it executes (note: we know that SQL execution is compiled and parsed).
-
PreparedStatementHandler: Prepared statements processors, inheritance BaseStatementHandler abstract class, corresponding to Java. SQL. PrepareStatement object processing, compared with the ordinary statements processors, it supports variable parameter SQL execution, PrepareStatement is the default and recommended statement processor. If a prepared command is found in the cache, it will be directly parsed and executed. Therefore, recompilation is reduced, system performance is improved, and SQL injection attacks are prevented.
-
CallableStatementHandler: Stored procedure processor, inheritance BaseStatementHandler abstract class, corresponding to Java. SQL. The processing of the CallableStatement object, is clear, it is used to call a stored procedure, increases the function call and output/input parameters of the stored procedure support.
In fact, ordinary statement processor, pre-execution statement processor and stored procedure processor, just Mybatis for JDBC statement execution object simple packaging, there is no special mystery, see the following JDBC statement execution object class diagram relationship can be clear.
- RoutingStatementHandler: The routing StatementHandler, which implements the StatementHandler interface, does exactly what it’s called. It does just that, and uses the three StatementHandler instances described above as its delegates. So when the executor builds the StatementHandler, I’m just directly new the RoutingStatementHandler instance.
// 1. The executor builds the statement handler instance
public StatementHandler newStatementHandler(...). {
// Build a routing statement handler!
StatementHandler statementHandler =
newRoutingStatementHandler(...) ;// Other logic ignores...
return statementHandler;
}
// 2.
public RoutingStatementHandler(...). {
// Construct a delegate instance of the specified type
switch (ms.getStatementType()) {
case STATEMENT:
delegate = newSimpleStatementHandler(...) ;break;
case PREPARED:
delegate = newPreparedStatementHandler(...) ;break;
case CALLABLE:
delegate = newCallableStatementHandler(...) ;break;
default:
throw new ExecutorException(
"Unknown statement type: "+ ms.getStatementType()); }}Copy the code
The default statement handler constructed by the executor for CRUD operations is PrepareStatementHandler, but can we specify the statement handler type?
Sure, for example we specify that the update user statement applies to the precompiled processing statement handler:
<! STATEMENT, PREPARED, CALLABLE -->
<update id="updateUser" statementType="STATEMENT">
update t_user set name = #{newName}
</update>
Copy the code
When Mybatis parses each statement in the mapper, it sets the statement handler type:
// Statement object parser
public class XMLStatementBuilder {
// Parse the statement node
public void parseStatementNode(a) {
// Sets the statement handler type
// The default is PREPARED
StatementType statementType =
StatementType.valueOf(
context.getStringAttribute(
"statementType", StatementType.PREPARED.toString() ) ); }}Copy the code
So, the statement executor interacts with the database:
Of course, the StatementHandler interface StatementHandler provides the basic interface. There is generally no need to customize the implementation class, so we can simply take a look at it:
ParamerHandler — Parameter handler
ParameterHandler is a ParameterHandler interface that converts user-passed parameters into the parameters required for a JDBC Statement. The underlying data conversion is handed over to TypeHandler, a type converter, as described below.
Obviously, there are only two StatementHandler instances that need to be converted to the passed argument:
- PrepareStatementHandler precompiled processor
- CallableStatementHandler Stored procedure handler
The basic statement processor BaseStatementHandler builds both the parameter handler and the result set handler during instance construction.
// Base statement handler
public abstract class BaseStatementHandler{
// When an instance is constructed
protected BaseStatementHandler(...).{
// Other logic can be ignored...
// 1. Build the parameter handler
this.parameterHandler = conf.newParameterHandler(...) ;// 2. Build the result set handler
this.resultSetHandler =
conf.newResultSetHandler(...);
}
}
Copy the code
The parameter handler interface is relatively simple, with only one default implementation class, DefaultParameterHandler, which has only two methods:
- 1. SetParameters sets parameters. This occurs when a CURD statement is executed and the statement processor sets the parameters
// Two processors are used:
// The precompiled processor PreparedStatementHandler
// Stored procedure handler CallableStatementHandler
public void parameterize(Statement statement) {
// Use the ParameterHandler object to set the value of Statement
parameterHandler.setParameters(statement);
}
Copy the code
Application Scenario For example, when querying the user object, set the name. The parameter processor assigns the value to the name property placeholder in combination with the type processor.
<select id="queryUSer">
select * from t_user where name = #{name}
</select>
Copy the code
- GetParameterObject gets parameters when the result set is returned. The result set handler gets object parameters. It is worth noting that this method is only used for the stored procedure handler CallableStatementHandler.
// Default result set handler
public class DefaultResultSetHandler{
// Process the output parameters
public void handleOutputParameters(...). {
// Get parameters
final Object parameterObject =
parameterHandler.getParameterObject();
// Other stored procedure output parameters processing logic...}}Copy the code
10. ResultSetHandler — ResultSetHandler
ResultSetHandler is a resultSet handler interface that converts a resultSet object returned by JDBC into a collection of type List. It is created when the statement handler builds the instance. The underlying data conversion work is handed over to the TypeHandler, which has one default implementation class DefaultResultSetHandler. This interface has three methods:
- HandleResultSets: Handles the result set, completes the mapping and returns the result object
- HandleCursorResultSets: Handles cursor objects
- HandleOutputParameters: Handles the output parameters of the stored procedure
The basic processing of the result set returned by JDBC by the result set processor is to obtain the resultType or resultMap mapping relationship specified in the Mapper, then traverse and parse each column of data in the result set, and perform related reflection processing through MetaObject objects at the bottom.
For the detailed source code logic, we will follow the source code analysis section in detail.
Not to speak is not Chinese
TypeHandler — type converter
TypeHandler is a type converter/processor interface that maps and converts Java and JDBC data types. When a Statement object is set as a parameter, the JavaType is converted to JdbcType. JdbcType is also converted to JavaType when the Statement return result set is encapsulated and mapped.
Generally, we can directly use Mybatis built-in type processor, a simple look at 65+, of course, we can customize the type processor according to business needs, in order to deal with complex types or non-standard types.
Specific measures are as follows:
1, implement org. Apache. Ibatis. The TypeHandler interface;
2, inheritance, org. Apache. Ibatis. The BaseTypeHandler class.
The BaseTypeHandler class as an abstract class already implements the TypeHandler interface.
We see that the interface TypeHandler defines four methods:
public interface TypeHandler<T> {
// Set parameters
void setParameter(
PreparedStatement ps,
int i, T parameter,
JdbcType jdbcType);
// Get conversion results based on column names
T getResult(ResultSet rs, String columnName);
// Get the conversion result based on the column subscript
T getResult(ResultSet rs, int columnIndex);
// Get the output of the stored procedure according to the column subscript
T getResult(CallableStatement cs, int columnIndex);
}
Copy the code
In fact, I previously introduced the core configuration of Mybatis, there is a strong introduction of type processor, there is no need to repeat (in fact, lazy), interested friends can directly see our previous article “Mybatis series full solution (four) : Mybatis configuration file XML overview of the type processor TypeHandler introduction.
12. MappedStatement — Statement object
MappedStatement statement object, it is in our Mapper Mapper maintained in each statement, such as < select | update | delete | insert >, Each statement in Mybatis is parsed using the statement builder XMLStatementBuilder:
The whole parsing process is divided into four steps:
- XMLConfigBuilder parses mapper:
// Configuration Configures the parser
public class XMLConfigBuilder{
// Parse the mapper
private void mapperElement(a){
// Create a mapper parse instance
XMLMapperBuilder mapperParser =
newXMLMapperBuilder(...) ;// Start parsingmapperParser.parse(); }}Copy the code
2. Mapping object parser XMLMapperBuilder parses statements
// Map object resolver
public class XMLMapperBuilder{
// 1
public void parse(a) {
// Parse the mapper file
configurationElement(
parser.evalNode("/mapper"));
}
// 2
private void configurationElement(XNode context) {
// Build the statement object
buildStatementFromContext(
context.evalNodes(
"select|insert|update|delete"));
}
// 3. Finally call the statement parser
private void buildStatementFromContext(a){
// Create a statement parsing instance
XMLStatementBuilder statementParser =
new XMLStatementBuilder();
// Parse the statement nodestatementParser.parseStatementNode(); }}Copy the code
The statement parser XMLStatementBuilder parses each node
// Statement parser
public class XMLStatementBuilder{
// Parse the statement node
public void parseStatementNode(a) {
// Build statement objects from statement helper classesbuilderAssistant.addMappedStatement(...) }}Copy the code
4. Add the statement helper class MapperBuilderAssistant to the statement collection
// Statement helper class
public class MapperBuilderAssistant{
// Add statement objects
public MappedStatement addMappedStatement(/ / eventually added to the configuration class statements set the configuration. The addMappedStatement (statement); }}Copy the code
SqlSource — SQL source
SqlSource is an SQL source interface that dynamically generates SQL statements in conjunction with parameterObject, a user-passed parameterObject, and encapsulates BoundSql objects. The SqlSource interface has five implementation classes: StaticSqlSource, DynamicSqlSource, RawSqlSource, ProviderSqlSource, VelocitySqlSource (this is just a test case, not a true template Sql source implementation class).
- StaticSqlSource: StaticSqlSource implementation class. All SQL sources eventually build an instance of StaticSqlSource, which generates the final executable SQL statement for use in a statement or prepareStatement.
- RawSqlSource: Native SQL source implementation class that parses and builds SQL statements with ‘#{}’ placeholders, or native SQL statements, and ultimately builds an instance of StaticSqlSource.
- DynamicSqlSource: a DynamicSqlSource implementation class that parses and builds SQL statements with the ‘${}’ substitution or statements with dynamic SQL (such as If/Where/Foreach, etc.), resulting in a StaticSqlSource instance.
- ProviderSqlSource: Annotated SQL source implementation class that will be distributed to RawSqlSource or DynamicSqlSource depending on the content of the SQL statement, and of course will eventually build the StaticSqlSource instance.
- VelocitySqlSource: Template SQL source implementation class. This is officially a test case, not a real template SQL source implementation class.
The SqlSource instance is created during the Configuration class Configuration parsing phase. Mybatis framework selects which data source instance to build based on three dimensions:
- The first dimension: client SQL configuration: XML or annotation.
- The second dimension: whether dynamic SQL is used in the SQL statement (if/ WHERE /foreach, etc.).
- The third dimension: whether the SQL statement contains the substitution ‘${}’ or the placeholder ‘#{}’.
The SqlSource interface has only one method, getBoundSql, which creates a BoundSql object.
public interface SqlSource {
BoundSql getBoundSql(Object parameterObject);
}
Copy the code
BoundSql — SQL statement
The BoundSql object stores dynamically generated SQL statements and parameter information. The BoundSql object is built from the actual SqlSource instance when the executor executes the CURD. BoundSql can be used to obtain SQL statements executed by the actual database. The system can build a Statement or prepare a Statement based on the SQL Statement.
public class BoundSql {
SQL statement, which may contain "?" A placeholder
private final String sql;
// Set of parameter attributes in SQL
private final List<ParameterMapping> parameterMappings;
// The actual parameter values passed in when the client executes the SQL
private final Object parameterObject;
// Copy the contents of the DynamicContext.bindings collection
private final Map<String, Object> additionalParameters;
// Build the meta-parameter object with additionalParameters
private final MetaObject metaParameters;
}
Copy the code
conclusion
It took two weeks for this paper to be basically finished. Following the core execution process of Mybatis database, we have roughly introduced several relative core apis in Mybatis. While building the design diagram of core architecture function, we sorted out the relevant knowledge context of API, which is basically clear at present.
For the problem is that of distress for the control content range scale, every article I hope to be comprehensive, to be careful, these two insists it is destined to the content of the article can’t be all dry, slightly understand people can only choose to skip reading, with knowledge of nutrition need to pay, self choice; At the same time, it will also lead to a huge length of content, resulting in the overall reading time is too long, not easy to quickly absorb.
Follow-up attempts to change the way of writing, try to output dry goods, content point to the end, for the need for detailed analysis of the content, we stand alone article interpretation.
After this article, the next part of this series we will talk about “Mybatis series complete solution (seven) : Dao layer two ways to implement”.
The article continues to update, wechat search “Pan Pan and his friends” the first time to read, there are surprises at any time. This article will be included on GitHub github.com/JavaWorld, about hot technology, frame, face classics, solutions, fishing skills, tutorials, videos, comics and so on, we will be the first time to the most beautiful posture, welcome Star ~ we will not only articles in the future! Want to enter the reader group of friends welcome to my personal number: Panshenlian, remarks “add group” we chat in the group, BIU ~