Interviewer: mybatis SQL execution process is so clear, copy it online!

Time:2021-3-1

preface

Many people may have been using mybatis all the time, but the SQL execution process of mybatis may not be clear to everyone. Now that you have come in, read through this article and you will get the following:

  • 1. How to bind mapper interface and mapping file
  • 2. Execution flow of SQL statement in mybatis
  • 3. Custom parameter setting processor typehandler in mybatis
  • 4. Customizing result set processor typehandler in mybatis

PS: This article is based on mybatis 3.5.5 source code

outline

In mybatis, data query by programming is mainly composed of the following lines of code:

SqlSession session = sqlSessionFactory.openSession();
UserMapper userMapper = session.getMapper(UserMapper.class);
List<LwUser> userList =  userMapper.listUserByUserName (lone wolf 1);
123

The first line is to get a sqlsession object, which has been analyzed in the last article. You can understand it in detailclick here The second line is to obtain the usermapper interface, and the third line is a line of code to implement the whole query statement process. Next, let’s carefully analyze the second and third steps.

Get mapper interface (getmapper)

The second step is to get a mapper interface through the sqlsession object. This process is relatively simple. Here’s what we call session.getMapper The running sequence diagram after the method is as follows:
Interviewer: mybatis SQL execution process is so clear, copy it online!

  • 1. After calling getmapper, the mapper object will be obtained from the configuration object, because the mapper interface will be loaded, parsed and stored in the configuration object when the project is started

Interviewer: mybatis SQL execution process is so clear, copy it online!

  • 2. Continue to call the getmapper method through the mapperregistry object property in the configuration object
    Interviewer: mybatis SQL execution process is so clear, copy it online!
  • 3. According to the type, the agent factory class corresponding to the current type is obtained from the knownmappers in mapperregistry object, and then the agent class corresponding to mapper is generated through the agent factory class
    Interviewer: mybatis SQL execution process is so clear, copy it online!
  • 4. Finally, we get the corresponding proxy class mapperproxy object of our interface
    Interviewer: mybatis SQL execution process is so clear, copy it online!
    Mapperproxy can see that the invocationhandler is implemented, using theJDK dynamic proxy
    Interviewer: mybatis SQL execution process is so clear, copy it online!
    Now that the mapper acquisition process is over, there is a problem. When did the data in the HashMap attribute knownmappers in the mapperregistry object be saved?

When are mapper interfaces and mapping files associated

Mapper interface and its mapping file are stored when mybatis config configuration file is loaded. The following is the sequence diagram:
Interviewer: mybatis SQL execution process is so clear, copy it online!

  • 1. First, we will manually call the build() method in the sqlsessionfactorybuilder method
    Interviewer: mybatis SQL execution process is so clear, copy it online!
  • 2. Then an xmlconfigbuilder object is constructed and its parse method is called
    Interviewer: mybatis SQL execution process is so clear, copy it online!
  • 3. Then we will continue to call our parseconfiguration to parse the configuration file. In this way, we will parse the top-level nodes of the global configuration file respectively. We will not look at the others first, but we will directly look at the mappers node in the end
    Interviewer: mybatis SQL execution process is so clear, copy it online!
  • 4. Continue to call your mapperelement to parse the mappers file (this method is relatively long, so the font is reduced by 1 in order to facilitate the integrity of the screenshot). You can see that there are four ways to parse the mappers node configuration, corresponding toFour mapper configurationsThe two methods in the red box are directly configured XML mapping files, and the two methods in the blue box are parsing and directly configuring mapper interface, which can also be explained here,Either way, mybatis will eventually associate the XML Mapping file with mapper interface
    Interviewer: mybatis SQL execution process is so clear, copy it online!
  • 5. Let’s first look at the second and third methods (the parsing method of directly configuring the XML Mapping file). We will build an XML maperbuilder object and call its parse method.
    Interviewer: mybatis SQL execution process is so clear, copy it online!
    But there is a problem here. If there are multiple inheritance or multiple dependencies, they may not be fully parsed here. For example, if three mapping files depend on each other, only one can be loaded in if (assuming the worst case),2 failures, and then go to the following, only one code other than if can be loaded,One more will fail(in the following code, it will only be processed once, and if it fails again, it will not continue to join incomplete resultmaps.)
    Interviewer: mybatis SQL execution process is so clear, copy it online!
    Of course, this will still be parsed. When the query is executed later, it will be parsed again through continuous traversal. However, it should be noted that mutual reference will lead to parsing failure and error reporting. Therefore, we should avoid circular dependency in the development process
  • 6. After parsing the mapping file, call its own method bindmapperfornamespace to start binding mapper interface and mapping file
    Interviewer: mybatis SQL execution process is so clear, copy it online!
  • 7. Calling addmapper of configuration object
    Interviewer: mybatis SQL execution process is so clear, copy it online!
  • 8. Call the addmapper method in the mapperregistry attribute of the configuration object. This method is to formally add the mapper interface to knownmappers, so the above getmapper can directly obtain:
    Interviewer: mybatis SQL execution process is so clear, copy it online!
    So far, we have completed the binding of mapper interface and XML Mapping file
  • 9. Note that the code in the red box above calls the parse method again. This parse method is mainly used to parse annotations, such as the following statement:
@Select("select * from lw_user")
    List<LwUser> listAllUser();
12

So in this method, we will parse @ select and other annotations,The parse method will parse the XML Mapping file at the same time. As we mentioned above, the mappers node has four configuration methods, two of which are mapper interface. The mapper interface will directly call the addmapper interface first, and the mapping file will not be parsed. Therefore, entering the parse method parse, you need to try to parse the XML Mapping file again.
Interviewer: mybatis SQL execution process is so clear, copy it online!
After parsing, the method in mapper interface will be parsed, and theThe fully qualified class name of each method is used as the keySave the mappedstatements property in configuration.

It should be pointed out that the same value will be stored twice when it is stored here,A fully qualified name is used as the key, and the other is to use only the method name (the ID of the SQL statement) as the key
Interviewer: mybatis SQL execution process is so clear, copy it online!
So the final mapped statements will be as follows:
Interviewer: mybatis SQL execution process is so clear, copy it online!
In fact, if we program through the interface, we always get getstatement based on the fully qualified name,Therefore, even if there are duplicate names, it will not affect us. In fact, the reason for doing so is to be compatible with the usage of earlier versions, that is, to query directly through the method name instead of through the interface

session.selectList("com.lonelyWolf.mybatis.mapper.UserMapper.listAllUser");
1

Here, if shortname is not repeated, you can query it directly by shortname:

session.selectList("listAllUser");
1

However, once the shortname is repeated, the following exception will be thrown:
Interviewer: mybatis SQL execution process is so clear, copy it online!
The exception here is actually thrown out by the get method of strickmap
Interviewer: mybatis SQL execution process is so clear, copy it online!

SQL execution process analysis

As we mentioned above, the obtained mapper interface is actually packaged as a proxy object, so we must execute the proxy object method to execute the query statement. Next, we will analyze the query process with the proxy object mapperproxy of mapper interface.

The whole SQL execution process can be divided into two steps

  • 1、 Looking for SQL
  • 2、 Execute SQL statement

Looking for SQL

First of all, let’s look at the sequence diagram of finding SQL statements
Interviewer: mybatis SQL execution process is so clear, copy it online!

  • 1. Understandingproxy patternAs we all know, after calling the method of the proxy object, what is actually executed is the invoke method of the proxy object
    Interviewer: mybatis SQL execution process is so clear, copy it online!
  • 2. Because we didn’t call the method in the object class here, we must use else. The method cachedinvoker in mappermethodinvoker, an internal class of mapperproxy, will continue to be called in else. There will be a judgment to determine whether we are the default method. Because the default method can be added to the interface in JDK1.8, and the default method is not an abstract method, so it also needs special processing (I will take it from the cache at the beginning, and I will cache related knowledge) We won’t talk about it here. We will write a separate article to analyze it later.
    Interviewer: mybatis SQL execution process is so clear, copy it online!
  • 3. Next, construct a mappermethod object, which encapsulates the corresponding method information and the corresponding SQL statement information in mapper interface
    Interviewer: mybatis SQL execution process is so clear, copy it online!
    In this way, the SQL statement to be executed, request parameters and method return values will be parsed and encapsulated as mappermethod objects, and then the SQL statement can be ready to be executed later

Execute SQL statement

Let’s take a look at the sequence diagram of executing SQL statements first:
Interviewer: mybatis SQL execution process is so clear, copy it online!
1. Let’s continue with the above process and enter the execute method
Interviewer: mybatis SQL execution process is so clear, copy it online!

  • 2. Here, we will decide how to execute according to the statement type and the return value type. What I return here is a collection, so we enter the executeformany method:
    Interviewer: mybatis SQL execution process is so clear, copy it online!
  • 3. First of all, the previously saved parameters will be converted. Then, we will go around this circle and return to the starting point of the sqlsession object. We will continue to call the selectlist methodInterviewer: mybatis SQL execution process is so clear, copy it online!
  • 3. Next, the process is delegated to execute to execute the query method. Finally, the queryfromdatabase method is called
    Interviewer: mybatis SQL execution process is so clear, copy it online!
  • 4. After that, I finally want to get to the point. Generally speaking, the way to start with do is to really do things. This naming method is also used in many places in spring
    Interviewer: mybatis SQL execution process is so clear, copy it online!
    Note that the previous SQL statement is still a place holder, and the parameters are not set in it. Therefore, when calling the preparestatement method on the line above return to create a statement object, the parameters will be set to replace the place holder. How to set parameters? Let’s skip first. When the process is finished, we will analyze parameter mapping and result set mapping separately.

5. Continue to enter the query method of the preparedstatementhandler object. You can see that this step is to call the execute method in the JDBC operation object Preparedstatement, and the last step is to convert the result set and return it.
Interviewer: mybatis SQL execution process is so clear, copy it online!
At this point, the analysis of the whole SQL statement execution process is over. In the middle of the process, the storage and conversion of some parameters are not in-depth, because the conversion of parameters is not the core. As long as we know the whole data flow process, we can also have our own implementation mode. As long as we save it, we can parse it again and read it out.

Parameter mapping

Now let’s take a look at how parameters are set before executing the query. Let’s enter the preparestatement method first
Interviewer: mybatis SQL execution process is so clear, copy it online!
We find that in the end, we call parameterize in statementhandler to set parameters. Next, in order to save space, we will not go step by step and go directly to the method of setting parameters
Interviewer: mybatis SQL execution process is so clear, copy it online!
The above basetypehandler is an abstract class. Setnonnullparameter is not implemented. It is all implemented by subclasses, and each subclass corresponds to a type of database. The default subclass stringtypehandler is shown in the figure below. There is no other logic in it, just setting parameters.
Interviewer: mybatis SQL execution process is so clear, copy it online!
You can see that the setstring method in JDBC is called in string, and the setint method is also called in int.
See these subclasses, if you have read what I said beforeMybatis parameter configurationIt should be obvious that these subclasses are typehandlers provided by the system by default. These default typehandlers are registered and bound to Java objects by default
Interviewer: mybatis SQL execution process is so clear, copy it online!
Because mybatis provides the mapping of common data types by default, we can omit the parameter mapping relationship when writing SQL. We can directly use the following methods. The system can automatically select the appropriate typehandler for mapping according to our parameter types:

select user_id,user_name from lw_user where user_name=#{userName}
1

The above statement is actually equivalent to the following one:

select user_id,user_name from lw_user where user_name=#{userName,jdbcType=VARCHAR}
1

Or we can directly specify typehandler:

select user_id,user_name from lw_user where user_name=#{userName,jdbcType=VARCHAR,typeHandler=org.apache.ibatis.type.IntegerTypeHandler}
1

Here, because we have configured typehandler, we willPriority is given to the configured typehandlerThe default mapping will not be read again. If the type does not match, an error will be reported directly
Interviewer: mybatis SQL execution process is so clear, copy it online!
Many people should know that if we customize a typehandler, we can configure it to our own custom class.
So let’s see how to customize a typehandler

Custom typehandler

User defined typehandler needs to implement the basetypehandler interface. Basetypehandler has four methods, including result set mapping. In order to save space, the code is not written:

package com.lonelyWolf.mybatis.typeHandler;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class MyTypeHandler extends BaseTypeHandler<String> {

    @Override
    public void setNonNullParameter(PreparedStatement preparedStatement, int index, String param, JdbcType jdbcType) throws SQLException {
        System.out.println ("custom typehandler is in effect");
        preparedStatement.setString(index,param);
    }
1234567891011121314151617

Then we rewrite the above query statement:

select user_id,user_name from lw_user where user_name=#{userName,jdbcType=VARCHAR,typeHandler=com.lonelyWolf.mybatis.typeHandler.MyTypeHandler}
1

After that, you can see that the custom typehandler takes effect
Interviewer: mybatis SQL execution process is so clear, copy it online!

Result set mapping

Next, let’s take a look at the mapping of the result set, and return to the last method of executing the SQL process above:

resultSetHandler.handleResultSets(ps)
1

The logic in the result set mapping is relatively complex, because there are many cases to consider. Here we will not go into every detail and go directly to the code for formally parsing the result set. The following five code fragments are a simple but complete parsing process:
Interviewer: mybatis SQL execution process is so clear, copy it online!
Interviewer: mybatis SQL execution process is so clear, copy it online!
Interviewer: mybatis SQL execution process is so clear, copy it online!
Interviewer: mybatis SQL execution process is so clear, copy it online!
Interviewer: mybatis SQL execution process is so clear, copy it online!
We can also see from the above code fragment that parsing result set is very complicated. Just like the complex query we introduced in the last article, one query can nest other queries continuously, and there are some complex features such as delayed loading
So there are many logical branches, but no matter how to deal with it, the final core is the above set of processes, and eventually the typehandler will be called to get the query results.

Yes, you guessed right. This is the typehandler of our mapping parameters above, because typehandler is not only a parameter setting method, but also a result set method (omitted when setting parameters above).

Custom typehandler result set

So let’s use the mytypehandler example above to rewrite the value method (omitting the parameter setting method)

package com.lonelyWolf.mybatis.typeHandler;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class MyTypeHandler extends BaseTypeHandler<String> {

    /**
     *Setting parameters
     */
    @Override
    public void setNonNullParameter(PreparedStatement preparedStatement, int index, String param, JdbcType jdbcType) throws SQLException {
        System.out.println (setting parameters > Custom typehandler is in effect);
        preparedStatement.setString(index,param);
    }
    /**
     *Get results by column name
     */
    @Override
    public String getNullableResult(ResultSet resultSet, String columnName) throws SQLException {
        System.out.println ("get result according to columnname - > user defined typehandler takes effect");
        return resultSet.getString(columnName);
    }

    /**
     *Get the result based on the subscript of the column
     */
    @Override
    public String getNullableResult(ResultSet resultSet, int columnIndex) throws SQLException {
        System.out.println ("get result according to columnindex - > user defined typehandler takes effect");
        return resultSet.getString(columnIndex);
    }

    /**
     *Process the result set of stored procedures
     */
    @Override
    public String getNullableResult(CallableStatement callableStatement, int columnIndex) throws SQLException {
        return callableStatement.getString(columnIndex);
    }
}
12345678910111213141516171819202122232425262728293031323334353637383940414243444546

To override mapper mapping file configuration:

 <resultMap id="MyUserResultMap" type="lwUser">
        <result column="user_id" property="userId" jdbcType="VARCHAR" typeHandler="com.lonelyWolf.mybatis.typeHandler.MyTypeHandler" />
        <result column="user_name" property="userName" jdbcType="VARCHAR" />
    </resultMap>

<select id="listUserByUserName" parameterType="String" resultMap="MyUserResultMap">
        select user_id,user_name from lw_user where user_name=#{userName,jdbcType=VARCHAR,typeHandler=com.lonelyWolf.mybatis.typeHandler.MyTypeHandler}
    </select>
12345678

After execution, the output is as follows:
Interviewer: mybatis SQL execution process is so clear, copy it online!
Because we only configure one property above the property, we only output it once.

Work flow chart

The flow of code is described above, which may be a little dizzy. So let’s draw a flow chart between main objects to show the main workflow of mybatis more clearly
Interviewer: mybatis SQL execution process is so clear, copy it online!
As can be seen from the above workflow diagram, there are four objects under sqlsession, which are also very important. When we learn interceptors later, we will intercept these four objects. We will analyze the specific details of these four objects in the next article.

summary

This paper mainly analyzes the SQL execution process of mybatis. In the process of analyzing the process, we also demonstrated how to customize typehandler to realize the user-defined parameter mapping and result set mapping. However, the default mapping provided in mybatis can meet most of the requirements. If we need special treatment for some attributes, we can use the user-defined typehandle to realize it. I believe if we understand this article, You should at least have a clear understanding of the following points:

  • 1. How to bind mapper interface and mapping file
  • 2. Execution flow of SQL statement in mybatis
  • 3. Custom parameter setting processor typehandler in mybatis
  • 4. Customizing result set processor typehandler in mybatis

Of course, many of the details are not mentioned, and we don’t need to be able to understand every line of code when we look at the source code. For example, we have a slightly more complex business system. Even if we are project developers, if we are not responsible for a certain module, I’m afraid it’s difficult to understand the meaning of every line of code. So it’s the same for mybatis and other frameworks. First of all, we should start from the overall situation, master the overall process and design ideas, and then if we are interested in some implementation details, we can have an in-depth understanding.

Author: Twin lone wolf
Source:https://blog.csdn.net/zwx9001…

Finally, share a set of micro service e-commerce project tutorial (data notes + video)Pay attention to the official account below for interview.Data + project actual data (e-commerce / aggregate payment /)For reference:https://www.laopaojava.com/posts/38510.html
Interviewer: mybatis SQL execution process is so clear, copy it online!