start
Time is limited, ability is limited, if there is an incorrect place, welcome to correct.
Speaking of MyBtis-Plus, to understand its source code, you need to know what MyBtis-Plus does in your project. The framework is easy to use, simple, and popular, so here’s a copy of its features from the myBtis-Plus introduction.
- Non-invasive: only enhanced but not changed, introducing it will not affect the existing engineering, as smooth as silk
- Small loss: the basic CURD will be automatically injected when started, the performance is basically loss-free, and the operation is directly object-oriented
- Powerful CRUD operations: The built-in universal Mapper and universal Service can realize most CRUD operations of a single table with only a few configurations. There is a powerful conditional constructor to meet various requirements
- Support for calls in the form of Lambda: by using Lambda expressions, it is convenient to write all kinds of query conditions, without worrying about field error
- Support for automatic generation of primary keys: support up to four primary key policies (including distributed unique ID generator – Sequence), configurable, perfect to solve the primary key problem
- Support for ActiveRecord mode: Support for ActiveRecord mode invocation, entity classes only need to inherit Model class to perform powerful CRUD operations
- Support for custom global generic operations: Support for global generic method injection (Write once, use Anywhere)
- Built-in code generator: Use code or Maven plug-in to quickly generate Mapper, Model, Service, Controller layer code, support template engine, and more custom configuration for you to use
- Built-in pagination plugin: Based on MyBatis physical pagination, developers do not need to care about the specific operation, after configuring the plugin, write pagination is equivalent to normal List query
- Paging plugin supports multiple databases: support MySQL, MariaDB, Oracle, DB2, H2, HSQL, SQLite, Postgre, SQLServer and other databases
- Built-in performance analysis plug-in: output Sql statements and their execution time. It is recommended to enable this function when developing tests to quickly catch slow queries
- Built-in global interception plug-in: Provides intelligent analysis and block of delete and UPDATE operations in all tables. You can also customize interception rules to prevent misoperations
In summary, Mybatis-Plus did three things in the project.
- Code generator.
- Startup time operations (database configuration, Mapper scanning, etc.).
- CRUD operations in the project.
Here’s a look at how Mybatis-Plus works at startup and during CRUD in a project.
At the start
If you want the configuration to take effect automatically when the project starts, you need to know how to write a SpringBoot Starter and have written one yourself before. There is a meta-INF folder under the Resources folder of myBatis -plus-boot-starter
additional-spring-configuration-metadata.json
This is used to prompt when we write Mybatis — plus related configuration in properties or yML files.spring.factories
Automatic configuration is performed when the project starts. The automatic startup class configured inside# Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoCon figuration
MybatisPlusAutoConfiguration
@Configuration
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})// The system has the specified class
@ConditionalOnSingleCandidate(DataSource.class)// There is only one specified Bean in the container, or this Bean is the preferred Bean
@EnableConfigurationProperties(MybatisPlusProperties.class)// Provide support for beans with @ConfigurationProperties annotation
@AutoConfigureAfter(DataSourceAutoConfiguration.class)// Load one configuration class after another
public class MybatisPlusAutoConfiguration implements InitializingBean {
Copy the code
This class, because it implements the InitializingBean interface, gets the afterPropertiesSet method, which is automatically invoked after the Bean is initialized. There are also three methods annotated with @ConditionalonMissingBean.
This method creates beans by SpringBoot when SqlSessionFactory is not configured and saves them to the container.
This method creates beans by SpringBoot when the SqlSessionTemplate is not configured and saves them to the container.
This method is not configuredMapperFactoryBean
Beans are created by SpringBoot and stored in the container.
A method into com. Baomidou. Mybatisplus. Autoconfigure. MybatisPlusAutoConfiguration# sqlSessionFactory there is one MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
MybatisSqlSessionFactoryBean
This class implements three interfacesFactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent>
FactoryBean
: Indicates that factory mode is usedInitializingBean
:afterPropertiesSet
Called when the property is set (when the Bean is created)ApplicationListener
It’s a listener. It’s listening toApplicationContext
Initialize or refresh events, which are called when initialized or refreshed. Parses all the unprocessed statement nodes in the cache. It is recommended to call this method once all the mappers are added as it provides fail-fast statement validation. To refreshMappedStatement
Then watchcom.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean#afterPropertiesSet
This method, in this method, is calledcom.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean#buildSqlSessionFactory
buildSqlSessionFactory
Simply create an SqlSessionFactory instance, but there’s a lot going on in this method.
- First parse the configuration of Mybatis.
- None Configuration Start related configurations
- Initialize the ID-work and print the Banner
- If the dbType is not configured, it is automatically obtained
- Custom enumeration class scan processing
- Scan alias package
- Add the interceptor plug-in
- If it is an XML configuration, parse the XML configuration file
- According to the
mapperLocations
parsingMapper
file - And finally, create
SqlSessionFactory
And return.
There is a problem here. The database type is set to Mysql in the configuration class, but it is still set to Other.
@Bean
public GlobalConfig globalConfig(a) {
GlobalConfig conf = new GlobalConfig();
DbConfig dbConfig = new DbConfig();
dbConfig.setDbType(DbType.MYSQL);
conf.setDbConfig(dbConfig);
return conf;
}
Copy the code
Because this object is new, it is not managed by Spring. If insteadResource
orAutowired
Injection, startup error.But it doesn’t matter, because it automatically determines the database type based on the Connection’s MetaData.
Now let’s look at this part of the method.That’s the one that mattersxmlMapperBuilder.parse();
thisparse
Method is used to parse an XML file.In the box, parse the interface file.
org.apache.ibatis.builder.annotation.MapperAnnotationBuilder#parseStatement
It is null, so it is not entered. This method is mainly used for parsingInsert
,Select
,Update
,Delete
andSelectProvider
,InsertProvider
,UpdateProvider
,DeleteProvider
The eight annotated methods, which are not in the project, are nullThe real injection is herecom.baomidou.mybatisplus.core.injector.AbstractSqlInjector#inspectInject
this.getMethodList(mapperClass)
The following injector is calledcom.baomidou.mybatisplus.core.injector.DefaultSqlInjector#getMethodList
com.baomidou.mybatisplus.core.injector.AbstractMethod#inject
com.baomidou.mybatisplus.core.injector.AbstractMethod#injectMappedStatement
Let’s do a deleteById,Mybatis-Plus
Here’s the secret to automatically injecting basic CurdsOf course, there is one last checkorg.springframework.dao.support.DaoSupport
org.mybatis.spring.mapper.MapperFactoryBean#checkDaoConfig
CRUD operations in the project
Used in projectsMybatis-Plus
With the exception of basic CRUD operations, SQL is mostly assembled using Lambda expressions.Mybatis-Plus
AR mode, will not be discussed for the moment.
Let’s look at this from a simple query SQL,Mybatis-Plus
How the SQL is assembled.This is aMybatis-Plus
Unit tests for the project
com.baomidou.mybatisplus.test.MybatisTest#test
This method is called
com.baomidou.mybatisplus.core.mapper.BaseMapper#selectCount
When it comes to Mybatis CRUD operations, there are two classes.
com.baomidou.mybatisplus.core.override.MybatisMapperProxy
com.baomidou.mybatisplus.core.override.MybatisMapperProxyFactory
MybatisMapperProxy implements the InvocationHandler interface and uses JDK dynamic proxy. While MybatisMapperProxyFactory this class all generated Mapper binding agent. In the org. Mybatis. Spring. SqlSessionTemplate# getMapper method is called for, is the JDK dynamic proxy class of production.
Breakpoint debugging
First get MapperGetting the proxy class
Access to SQL
com.baomidou.mybatisplus.core.conditions.AbstractWrapper#doIt
com.baomidou.mybatisplus.core.conditions.segments.MergeSegments#add
com.baomidou.mybatisplus.core.override.MybatisMapperMethod#MybatisMapperMethod
org.apache.ibatis.binding.MapperMethod.SqlCommand#SqlCommand
org.apache.ibatis.binding.MapperMethod.SqlCommand#resolveMappedStatement
As you can see, the query statement first concatenates the previous part and then dynamically concatenates the query criteria based on the lambda expression. So Mybatis-Plus is difficult to implement using lambda multi-table join queries.
In this methodorg.apache.ibatis.binding.MapperMethod.MethodSignature#MethodSignature
Set method signature.
Execute SQLcom.baomidou.mybatisplus.core.override.MybatisMapperMethod#execute
maysqlSegment
As the “”,columnMap
To null. Because when I break here, it’s all empty. (It’s not clear why.)
SQL Execution Process
Mybatis will createCacheKey each time it is queried. If the second query hits, it will go to cache. If the second query does not hit, it will go to basic query. And each query calls CachingExecutor first, and BaseExecutor after no cache hit.
org.apache.ibatis.session.defaults.DefaultSqlSession#selectOne(java.lang.String, java.lang.Object)
org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object)
org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object, org.apache.ibatis.session.RowBounds)
org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler)
org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)
org.apache.ibatis.executor.BaseExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)
org.apache.ibatis.executor.BaseExecutor#queryFromDatabase
conclusion
Why do you want to look at the source code? In fact, there are two reasons. One is to wonder why a BaseMapper can be used without basic CRUD. Second, it’s fun to write SQL for lambda expressions, and I want to see if I can modify it to support multiple table joins. Although it is Mybatis-Plus source code reading, in fact, there are most of Mybatis source code, read the source code does have a lot of benefits, at least now know how SQL injection, Mybatis level one cache is what, JDK dynamic proxy and so on. I also got a better understanding of Mybatis Plus.
If you want to support multiple table join queries, you need to add a new basic method, SQL statement only one SELECT, and then join leftJoin, rightJoin, join, on, using, union and other methods, from the table to parameters, all dynamically generated. It might work.
Although a lot of analysis, but this is only a general main process, many details have not been analyzed, there must be some missing places. Such as com. Baomidou. Mybatisplus. Core. Enums. SqlMethod. More knowledge or we go to find it together. Again, time is limited, capacity is limited, if there are mistakes, welcome to correct. Reprint please indicate.
This article was typeset using MDNICE