This is the 11th day of my participation in the August More Text Challenge. For details, see:August is more challenging

In this article, we summarize how the MyBatis interface executes SQL. In fact, we track the answers with the following questions:

  1. How was the Mapper interface discovered by Spring?
  2. How can mapper interfaces be automatically injected?
  3. How do mapper interface methods execute the corresponding SQL?

The whole process

The process from mapper interface to SQL execution can be divided into two big steps:

  1. Mapper proxy object creation.
  2. Execution of the agent’s mapper.

Mapper proxy object creation

  • First, by default, SpringBoot only scans for configured packages or class files under the default package and configures them@Configuration.@ComponentAnd so on. Since myBatis’ mapper interfaces can also be injected, they must have been scanned.
    • from@MapperScanEntry, the annotation is found@Import(MapperScannerRegistrar.class)aImportBeanDefinitionRegistrarThe configuration class.
    • The configuration classMapperScannerRegistrar.classThe function is to SpringBeanDefinitionRegistryregisteredMapperScannerConfigurerClass.
    • whileMapperScannerConfigurerTo achieve theBeanDefinitionRegistryPostProcessorInterface, so before it is initialized, it will be calledpostProcessBeanDefinitionRegistryIs created in this methodClassPathMapperScannerObject that scans the Mapper interface and generates itBeanDefinitionRegistered toBeanDefinitionRegistryGo inside.
    • At this point, the loading of the BeanDefinition of Mapper is complete. To summarize: what @mapPerscan does is scan the Mapper interface and create a BeanDefinition of MapperFactoryBean class.
  • When we use a service to refer to the mapper interface, we initialize it by referring to the BeanDefinition of the mapper interfaceMapperScannerConfigurerTo scan and register BeanDefinition work, set the class of these Mapper interfaces to beMapperFactoryBean, so the work of these beans is handed to itgetObject()Method.
  • Spring will passMapperFactoryBeanTo obtain the proxy class of the corresponding mapper interfacesqlSession.getMapper()To get to
    • The process of getMapper is the process of creating the dynamic proxy object MapperProxy.

Execution of the agent’s mapper

  • The MapperProxy object that we created internally holds a sqlSession object.

    • The sqlSession object is created at the same time as the SqlSessionFactory that we automatically configured. During the creation process, some configuration information related to SQL and MyBatis is loaded into a configuration property.
    • This configuration property has two more important properties inside it:mappedStatementsandmapperRegistry
      • MapperRegistry: Contains one internallyknownMappersMap: key is the interface class, and value isMapperProxyFactoryThe factory object is created using a JDK dynamic proxyMapperProxyObject.
      • MappedStatements: is also a map: key is encapsulated with the interface class + method name/method name, value is the corresponding SQL informationMappedStatementObject.
  • In addition to the SqlSession object, there is a map of MapperMethodInvoker to cache all the methods of the Mapper interface. This is lazily loaded. Every time the mapper method is executed, it wraps the corresponding Invoker and puts it into the cache.

  • When calling a method in mapper, it will first fetch it from the MapperMethodInvoker cache. If not, it will call cachedInvoker to create an instance of PlainMethodInvoker. Each invoker contains a MapperMethod object inside, so mapper’s methods are wrapped inside the object, and the invoker is just a shell.

  • The invoke method of the mapperMethod executes the execute method of the mapperMethod. This method calls the corresponding method of the SqlSession according to the SQL features. Take selectList as an example:

    MappedStatement ms = configuration.getMappedStatement(statement);
    return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
    Copy the code

    As you can see, we still take the SQL information from the CONFIGURATION of the SqlSession and hand it over to an Executor.

    This step is the interface and SQL correspondence to find the key step!

  • The following Executor execution process, is the JDBC call and the result of the encapsulation process, will not be repeated.

legend

Here are two illustrations to show the two processes:

Mapper Obtain the proxy object

The Mapper proxy object executes SQL

conclusion

How does the Mapper interface call SQL?

  • MapperScan scans all mapper interfaces and registers classes as Beandefinitions of MapperFactoryBean.
  • When Spring does automatic injection, it injects the Bean returned by MapperFactoryBean#getObject.
  • GetObject returns the MapperProxy object obtained from SQLSession.getMapper.
  • At this point, focus on two things in the Spring container: mapper proxy beans and sqlSession beans, which are tightly coupled.
  • MapperProxy is used to retrieve SQL information from the MappedStatement map in the configuration of the SqlSession and send it to executor for execution.
  • Executor will eventually work its way into the JDBC code logic.