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