Think about this share with questions
In the second half of 2020, I organized a sharing of the core principles of Mybatis in the company. Mastering the underlying source code can not only better investigate problems, but also learn from the excellent design. Just catch up with the golden three silver four interview season, here carding out the following questions for your reference
- Relationship between Mybatis and JDBC
- The.xml file defines how SQL statements are parsed
- Storage and implementation of Mapper interface in Mybatis
- Mybatis SQL execution process
- How to implement paging in Mybatis
Mybatis-3-3.4.x source code
The persistence layer thing
What is a JDBC
JDBC (JavaDataBase Connectivity) is Java database connection, said straightforward point is the use of Java language operation database
JDBC is used to send SQL statements in the Java language
JDBC theory
Originally, SUN wanted to provide an API that would work for all databases, but it proved to be almost impossible in practice
Because the databases provided by various vendors are so different, SUN company and database vendors discussed that SUN company should provide a set of standard API for accessing databases and corresponding database connection protocol standards, and then each vendor should provide a set of API interface for accessing their own databases according to the specifications
The end result: SUN provides a canonical API called JDBC, and vendors provide their own database API called drivers
What is Mybatis
Mybatis is an excellent ORM (Persistence layer) framework written in the Java language
Formerly an open source project of Apache iBatis, it was migrated to Google Code in 2010 and officially renamed Mybatis
The ORM persistence layer stores service data to disks and has long-term storage capability. As long as the disks are not damaged, the system can still read data after restarting in case of power failure
Relationship between Mybatis and JDBC
Prior to the persistence framework, any code that wanted to operate on a database had to operate through JDBC. The following example illustrates the relationship between the two
JDBC operation database
I believe that you have used Mybatis in the actual project, you can think about whether we have done the following things in our daily work:
- Have database drivers been loaded?
- Do you want to get a database connection from the driver?
- Have you created a Statement that executes SQL?
- Do you convert database returns to Java objects yourself?
- Have you ever closed three objects ina finally block?
See the above soul torture, can answer the first question of this sharing:
Mybatis encapsulates repeated operations in JDBC, and extends and optimizes some functions
Mybatis keyword description
📖 If you have not touched Mybatis source code related content before reading this article, it is recommended to read the following terms several times before reading down
SqlSession
Responsible for executing select, INSERT, update, delete and other commands, as well as obtaining mapper and managing transactions; Its bottom layer encapsulates the interaction with JDBC, which can be said to be one of the most core interfaces of MyBatis
SqlSessionFactory
The factory responsible for creating SQLSessions, once created, should exist for the duration of the application without additional creation
SqlSessionFactoryBuilder
The main constructor class is responsible for creating SqlSessionFactory, which uses the builder design pattern; Create the SqlSessionFactory
Configuration
Mybatis the most important configuration class, no one, store a large number of object configuration, you can see the source code feel
MappedStatement
MappedStatement is a data structure that stores SQL statements. The class attributes in the MappedStatement are converted from SQL tags in the parse.xml file
Executor
The SqlSession object corresponds to an Executor. Executor objects are used for adding, deleting, modifying, and querying methods, transactions, and caching operations
ParameterHandler
Parameter processor in Mybatis, the class relation is relatively simple
StatementHandler
StatementHandler is the Mybatis processor responsible for creating statements. StatementHandler creates statements of different functions based on different services
ResultSetHandler
ResultSetHandler is the handler that Mybatis parses the JDBC returned data and wraps it into the corresponding data structure in Java
Interceptor
Interceptor is the interface in Mybatis to define the common Interceptor, which defines the related implementation methods
Architecture design of Mybatis
Architecture diagram
Base support layer
Reflection module
Reflection is widely used in Java, but it is also a double-edged sword. Mybatis framework itself encapsulates the reflection module, provides more concise and easy-to-use API interface than the native reflection, and increases the cache of class metadata to improve the performance of reflection
Type conversion
The most important function of the type conversion module is to convert Java type to JDBC type when binding arguments to SQL statements, and then convert JDBC type to Java type when mapping result sets
Another feature is to provide an alias mechanism that simplifies the definition of configuration files
The log module
Logs are self-evident for the system, especially for testing, viewing information in the production environment, and troubleshooting errors. The mainstream log framework includes Log4j, Log4j2, S L F4J, etc. Mybatis log module function is to integrate these log frameworks
Resource to load
Mybatis encapsulates classloaders to determine the order in which they should be used to record class files and other resource files
Parser module
The parser module mainly provides two functions. One is to encapsulate the XPath class to parse the Mybatis-config. XML configuration file and map the configuration file during Mybatis initialization, and the other is to help with placeholders for dynamic SQL statements
.
Core processing layer
Configure the parsing
When Mybatis is initialized, the Configuration information in the Mybatis-config. XML file will be loaded, and the parsed Configuration information will be converted into A Java object and added to the Configuration object
📖 For example, a resultMap tag defined in.xml is parsed into a resultMap object
SQL parsing
If you’ve ever spelled a complex SQL statement by hand, you know how painful it can be. Mybatis provides dynamic SQL, adding many judgment loop tags, such as: if, WHERE, foreach, set, etc., to help developers save a lot of SQL spelling time
The function of SQL parsing module is to parse the dynamic SQL tags provided by Mybatis into SQL statements with placeholders, and replace the placeholders with arguments in the later stage
SQL execution
SQL execution involves several important objects: Executor, StatementHandler, ParameterHandler, ResultSetHandler
Executors are responsible for maintaining level 1 and level 2 caches and transaction commit rollback operations, such as queries, which are handed by executors to StatementHandler
StatementHandler uses ParameterHandler to bind arguments to SQL statements. The StatementHandler uses java.sql.Statement to execute SQL statements and obtain corresponding result set mappings
Finally, a ResultssetThandler parses the result set and converts the JDBC type into a custom object for the program
The plug-in
The plug-in module is a layer extension provided by Mybatis, which can intercept and execute custom plug-ins against the four major objects executed by SQL
Plug-in writing needs to be very familiar with Mybatis operation mechanism, so as to control the writing of plug-in security, efficient
The interface layer
The interface layer is only an interface SqlSession provided by Mybatis to the calling end. When calling the method in the interface, the calling end will call the module corresponding to the core processing layer to complete the database operation
q&a
The.xml file defines how Sql statements are parsed
When Mybatis creates SqlSessionFactory, XMLConfigBuilder parses the Mybatis-config.xml configuration file
Mybatis correlation parser
Mybatis parser module defines the related parser abstract class BaseBuilder, different subclasses are responsible for the implementation of different functions, using the Builder design pattern
XMLConfigBuilder is responsible for parsing the mybatis-config.xml configuration file
XMLMapperBuilder is responsible for parsing xxxmapper.xml generated by the business
.
Mybatis – config. XML parsing
XMLConfigBuilder parses mybatis-config.xml
The XMLConfifigBuilder#parseConfiguration() method parses the tag defined in mybatis-config.xml and populates it into the Configuration object
XxxMapper. XML parsing
Parse the configured mappers tag in XMLConfifigBuilder#mapperElement() to find the concrete.xml file, In addition, the select, INSERT, UPDATE, DELETE, resultMap labels are resolved into object information in Java
The xxxmapper. XML object is XMLMapperBuilder. The specific parsing method is parse().
Here is the answer to the question at hand
Mybatis uses SqlSessionFactory to parse Mybatis -config. XML, and then parses the child tags under the Configuration tag. When mappers are used, the.xml file is read according to the configuration. The tags in.xml are then parsed
Specific SELECT, INSERT, UPDATE, and DELETE tags are defined as MappedStatement objects, and the rest of the tags in the.xml file are resolved as Java objects depending on the mapping
MappedStatement
Let’s focus on the MappedStatement object and see how the properties of the class relate to SQL
The attributes provided in the MappedStatement object correspond to the SQL statements defined in the.xml file and are used to control the execution behavior of each SQL statement
Mapper interface storage and implementation
In the usual SSM framework we write, defined Mapper interface and.xml corresponding SQL file, in the Service layer directly injected xxxMapper can be
Also did not see the operation like JDBC operation database, Mybatis in the middle is how to omit these repetitive and tedious operations for us
Here use Mybatis source test class for verification, first define Mapper interface, save direct annotation definition SQL
SqlSession is used to obtain the Mapper operation database. The test method is as follows
Create a SqlSession
#1 Open a new SqlSession from SqlSessionFactory
Get the Mapper instance
AutoConstructorMapper is an interface, so why can it be instantiated as an object?
Dynamic proxy method invocation
#3 calls a specific method of the class through the object created. Here’s a bit more about operation #2
SqlSession is an interface that has a default implementation class DefaultSqlSession that contains the Configuration property
The Mapper interface information and the SQL statements in.xml are added to the MapperRegistry property of the Configuration when Mybatis is initialized
GetMapper in #2 is to get a Mapper from MapperRegistry
What are the class attributes of MapperRegistry
Config is the reference to the Configuration object that remains globally unique
KnownMappers key-class is the Mapper object, and value-mapperProxyFactory is the Mapper proxy factory derived from the Mapper object
Look again at the structure information for the MapperProxyFactory class
The mapperInterface attribute is a reference to the Mapper object, the key of the methodCache is a method in the Mapper, and the value is a MapperMethod generated by the Mapper parsing the corresponding SQL
📖 Mybatis designed the methodCache attribute with a lazy loading mechanism. The corresponding Method is not added on initialization, but is added on the first call
The runtime data for MapperMethod is shown below, which is easier to understand
As a practical example to help you understand the MapperRegistry class relationship, Mapper initializes the object state of the first call, and you can see that methodCache has a size of 0
Now that we know the class relationships of MapperRegistry, let’s go back to the MapperRegistry#getMapper() processing step 2
The core processing follows in the MapperProxyFactory#newInstance() method
MapperProxy inherits the InvocationHandler interface, and finally returns the dynamic Proxy implementation class returned by Java Proxy dynamic Proxy through newInstance()
This makes it clear why the interface can be instantiated in Step 2, returning the dynamic proxy implementation class of the interface
Mybatis Sql execution process
Follow Mybatis SQL execution flow chart for further understanding
It can be roughly divided into the following steps:
📖 in the previous content, know Mybatis Mapper is a dynamic proxy implementation, view SQL execution process, you need to follow the implementation of the InvocationHandler MapperProxy class
Implement add, delete, change and check
@Select(" SELECT * FROM SUBJECT WHERE ID = #{id}")
PrimitiveSubject getSubject(@Param("id") final int id);
Copy the code
Using the above method as an example, the caller obtains the Mapper dynamic proxy object through SqlSession and executes the Mapper method through InvocationHandler
In MapperMethod#execute, use MapperMethod -> SqlCommand -> SqlCommandType to determine the add, delete, change, and query methods
📖 SqlCommandType is an enumerated type, which can be UNKNOWN, INSERT, UPDATE, DELETE, SELECT, and FLUSH
Processing parameters
The query operation corresponds to the SELECT enumeration value. If else, it is determined whether the return value is set, no return value, single query, etc. Here, the single record is queried as the entrance
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
Copy the code
📖 here can explain a question that bothered me a while ago. That is, why does the Param object have two key-value pairs when the method has only a single @param (“id”) parameter
Continuing with sqlssession #selectOne, sqlSession is an interface, again depending on the implementation class DefaultSqlSession
Because single and query multiple and paging query are a way to go, the paging parameters are added during the query process
Actuator processing
In Mybatis source code, the default Executor is CachingExecutor, which uses decorator mode and keeps a reference to the Executor interface in the class. CachingExecutor adds caching function to the holding Executor
Delegate. query is the concrete executor. By default, the SimpleExecutor method is maintained in the BaseExecutor abstract superclass
The BaseExecutor#queryFromDatabase method performs cache placeholders and executes specific methods, and adds the query return data to the cache
The BaseExecutor#doQuery method is implemented by the specific SimpleExecutor
Execute SQL
Because we’re using parameter placeholders in our SQL, we’re using a PreparedStatementHandler object, and the Handler that executes the precompiled SQL, and actually uses the PreparedStatement to make the SQL calls
Return data parsing
Convert the JDBC return type to a Java type based on the resultSets and resultMap
5.4 How to implement paging in Mybatis
There are two ways to implement paging SQL with Mybatis. One is to add LIMIT when writing SQL, and the other is global processing
SQL paging
<select id="getSubjectByPage" resultMap="resultAutoMap">
SELECT * FROM SUBJECT LIMIT #{CURRINDEX} , #{PAGESIZE}
</select>
Copy the code
Interceptor paging
Mybatis supports a plugin extension mechanism that intercepts methods and entry levels for specific objects
When we add the plug-in, we need to implement the Interceptor interface, and then write the plug-in in the mybatis-config. XML configuration file or add relevant annotations. Only when myBatis initialization is resolved, can it be added to the plug-in container when the project is started
A List structure that stores all interceptors in a project is added through the Configuration#addInterceptor method
Focus on the plugin method in Interceptor#pluginAll. Interceptor is just an interface, and the plugin method can only be implemented by its implementation class
Plugin can be thought of as a utility class, and Plugin#wrap returns a dynamic proxy class
Here is a test Demo to look at the method’s runtime parameters
It’s a random Demo, but it’s not really different from a real plug-in
“Said
Relative to Spring, Mybatis is light enough, belongs to the entry level framework source code, but there are many design patterns used, which can be used for reference to the design of business code. At the same time, after mastering Mybatis to read SpringCloud, Dubbo source code to provide no small help, here also hope to read the article partners to Mybatis understanding can deepen the impression
Of course, how to say is the framework source code, it is impossible to master all through an article, readers can download the source code to run a few Demo, Mybatis source test class coverage is very comprehensive, do not worry about no direction. If the article is helpful to you, then point a concern to support it, wish you all the best.
Wechat search [source interest circle], pay attention to the public number after reply 123 receive content covers GO, Netty, Seata, SpringCloud Alibaba, development specifications, interview treasure book, data structure and other learning materials!
Reference content:
- MyBatis Technology Insider
- MyBatis website
- Source code download address
- Code generation image