Mybatis principle analysis (four)-query process

The principle analysis of the first three Mybatis can be viewed by clicking the link:

Mybatis principle analysis (1) parsing the global xml configuration file to generate SqlSessionFactory process

Mybatis principle analysis (two) the creation process of SqlSession

Mybatis principle analysis (three)-getMapper dynamically obtain interface implementation class

This article mainly talks about the query process of Mybatis based on the first three articles (same as adding, deleting and modifying), and it is also the core knowledge in Mybatis. I will not say much, but debug is respectful.

We said in the third article that the Mapper interface object we get is actually a proxy implementation class, the proxy is the MapperProxy object, and the MapperProxy object does not implement our Mapper interface, so when we call the interface method of the proxy class , The invoke method will give a condition to judge whether it is a method of the Object class (if there is no such judgment here, the program will report an error, see the explanation in Chapter 3 for details), it is obvious that we are calling the interface method, not the Object method , So our program comes directly to the cachedMapperMethod method, in-depth this method

 Here is actually an optimization, through a map container to cache our MapperMethed, the key is the called interface method Method, and the value is MapperMethod. There are two main attributes in this MapperMethod:

One of the SqlCommand objects, then let’s take a look at what’s in this SqlCommand and come to its constructor

First of all, it is an internal class of MapperMethod. There are two attributes in it, namely name and type. Then I will tell you the function of these two attributes directly. The name attribute gets what we call according to the passed interface and method. The full path name of the method goes to Configuration to get the corresponding MappedStatement, and then assigns the id of the MappedStatement object to the name, and the type is the same, which is also obtained by assigning the sqlCommandType of the MappedStatement. The other MethodSignature is also an internal class of MapperMethod. Its function is to determine what type of interface method the call is returned. I won't talk about it here.

The two classes mentioned above are actually laying the groundwork for the following, we click Next, come to the mapperMethod.execute method, and continue to in-depth.

It can be seen that the first thing here is to judge the method type by the type of SqlCommand in MapperMethod. Since we are a query method here, we have come to the SELECT branch.

In the SELECT branch, the return value of the method is judged again, and different if branches are taken according to the return value of the method. Obviously, the conditional judgment here is the credit of the MethodSignature we mentioned above. Next came the sqlSession.selectOne method, passed in the full path name of the method and the interface method parameters to be called, and continued to go deeper.

 Dive into the selectList method.

Go deeper.

 It can be seen that according to the name value of the previous sqlCommond, the corresponding MappedStatement object is obtained in the Configuration object, and then the executor.query method is called. Note that there is a wrapCollection method. From the name, we can see that it should be wrapped for our parameter object. Not much here. Then continue to dive into the query method.

The BoundSql object can be obtained through the getBoundSql method of the incoming MappedStatement, which contains our original SQL statement. And CacheKey is a key value used for our secondary cache, continue to dive into the query method below.

 The query method of CachingExecutor is called here, because we have configured the second level cache by default, so the Executor we actually execute will be wrapped by CachingExcutor. Here we talk about it in the second part, so we won't go into details. Then if there is no data in our secondary cache, we must call our real executor. Go deep into the delegate.query method.

This is similar to the second-level cache, it is first fetched from the local cache, that is, the first-level cache, so here we can know that the data source order in Mybatis is the second-level cache first, then the first-level cache, and finally the database. We dive into the queryFromDataBase method. 

In-depth doQuery method

 At this time, I came to the doQuery method of SimpleExecutor. I saw that I first got the Configuration object from the incoming MappedStatement object, and then called the newStatementHandler method of the configuration. This method returned a StatementHandler object and went deep into this method.

You can see that a RoutingStatemnetHandler object was created through the subclass first. What is this RoutingStatemnetHandler object? Let's take a look at its construction method.

In its properties, there is a StatementHandler property object. In fact, this property object is the real execution object of the method of this class. That is, the RoutingStatementHandler is actually a layer of packaging, and the creation of this object is based on our configuration file To determine the statementType set in, the default is to create a pre-compiled PrepareStatementHandler.

Then look at the code interceptorChain.pluginAll(statementHandler) in the red box above . It is a very familiar code. In fact, this code appeared when we initialized the Executor. We will also see this code in the following code. Related to the plugin mechanism of Mybatis. So what is this StatementHandler object? Let's execute the following code first.

After executing the newStatementHandler method, I came to the prepareStatement method below to go deep into this method.

It can be seen that in fact, our StatementHandler object is used to obtain the Statement object, and this Statement object is the Statement object in the jdk when we are learning JDBC programming, so the operation of the database by Mybatis actually encapsulates JDBC. Let's take a look at how the StatementHandler gets the Statement, and go into handler.prepare

You can see that the prepare method of prepareStatement is called, and this method is used in depth.

 You can see here that you get the sql statement from boundSql, and then call the connection.prepareStatement method to pass in the sql, so you get the Statement object.

Then came handler.parameterize(stmt), and then we went in and took a look.

The setParameters method of parameterHandler is called inside, and what is this parameterHandler object? Let's go back to initializing the PreparedStatementHandler before.

There is no such parameterHandler object in PreparedStatementHandler, and PreparedStatementHandler is inherited from BaseStatementHandler, so the initialization parameterHandler object should be in the construction method of its parent class BaseStatementHandler.

Come to the construction method of BaseStatementHandler, go deep into the configuration.newParameterHandler method.

It can be seen that both newParameterHandler and newResultSetHandler have a mechanism to call Mybatis plug-in. At present, we know that the four objects that can be intercepted by the Mybatis plug-in are Executor, StatementHandler, ParameterHandler, and ResultSetHandler . In fact , these four objects can be intercepted by the Mybatis plug-in. In Mybatis, we are used to call this Mybatis Four major components.

Guess you like

Origin blog.csdn.net/weixin_37689658/article/details/99617925