Mybatis integrates Spring to implement source code analysis of transaction management

I. Introduction

  I haven't read it completely, but I have seen some key points. I will make a record here. The process will be a bit messy. Later, it will be gradually added and finally archived as a complete process; I believe that those who have read the source code of the framework know that the process cannot be completely determined. After all, it is impossible to test all of them

, but the appearance of inspiration in the process of watching is very important (that is, intuition knows what the next steps should be, etc., but this self-consciousness is guessing rather than blinding, that is, in the process, it will be seen recursively. some key points instead of throwing dice to determine which subclass)

, so when you write it yourself, you can't write down the ideas generated in the process of reading in great detail, and the process is a bit jumpy. If you have any doubts, you'd better verify it yourself (the way is to search and see where the call is made, so just read it step by step. , some tricks are that if it is public, it is usually called by the external class [entry], if it is protected but not implemented

It means that there is an implementation in the class. If it has been implemented, it means that this method will be called in the parent class. If it is private, it will definitely be called in the current class);

Two: important classes or methods

1) For Mybatis

1. org.apache.ibatis.executor.Executor interface, there are probably three subclasses of BatchExecutor/ReuseExecutor/SimpleExecutor with a common parent class BaseExecutor, which is a component of the DefaultSqlSession class, and sqlSession objects such as selectOne are actually executed by executor;

2.org.apache.ibatis.transaction.Transaction interface, it has multiple implementation classes, but each implementation class has a DataSource attribute for generating data source and database service interaction;

3. SpringManagedTransaction is the key to support Spring's management of Mybatis transactions;

4.DefaultSqlSessionFactory

5.DefaultSqlSession

The important relationship between them: executor in sqlsession; transaction object in executor; datasource in transaction;

Process: The sqlsession execution code is delegated to be executed by the executor, and the executor obtains the connection through the transaction; and the transaction determines whether there is a ConnectionHolder object in the threadlocalmap; if not, it obtains one through the datasource, otherwise it returns the one stored in the threadlocalmap;

Three: Execution process

Such as: sqlSession.selectOne execution process:

3.1 selectOne finally goes to selectList;

3.2 Call the attribute executor.query method of sqlsession to execute;

3.3 Execute this sentence in the query method of BaseExecutor: list = this.queryFromDatabase(ms , parameter , rowBounds , resultHandler , key , boundSql) ; , so this sentence code is very critical;

3.4 Then look inside there is this.doQuery(ms , parameter , rowBounds , resultHandler , boundSql) ; method;

3.5 Then look at the doQuery method of SimpleExecutor (the source code is often based on instant inspiration, and it is difficult to fully describe the thinking and process of reading);

Supplementary start: 1. Then look at stmt = this.prepareStatement(handler , ms.getStatementLog()) ; , very important, because statement executes sql statements through its internal connection object;

2. Look at Connection connection = this.getConnection(statementLog) ; and then look inside: Connection connection = this.transaction.getConnection() ; Important , transaction finally appeared in the process of executing sql;

3. In the case of integrating Spring, it is known through the context of this article that this transaction is a SpringManagedTransaction object;

4. Then look at this.openConnection() of SpringManagedTransaction ; there is code:

this.connection = DataSourceUtils.getConnection(this.dataSource);
        this.autoCommit = this.connection.getAutoCommit();
        this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.connection, this.dataSource);

 

5. We look at DataSourceUtils.getConnection( this .dataSource);, and then go to the doGetConnection method where there is code:

ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(dataSource);
if(conHolder == null ...)
{get a new connection via dataSource}
else{
conHolder.getConnection(); //return a connection object in threadlocalmap;
}

Note that the above DataSourceUtils and here when TransactionSynchronizationManager and ConnectionHolder are classes in spring are not mybatis, and the threadlocal objects inside are static, so mybatis can obtain the connectionholder object placed in threadlocalmap in spring;

Whether spring generates connectionholder and whether it is placed in threadlocalmap is based on the txAdvice strategy;

 

end of supplement;

3.6 Then look at handler.query(stmt , resultHandler) ; then you can pick this method of RoutingStatementHandler;

3.7 will be delegated to other handlers for processing, which can be tentatively set as the PreparedStatementHandler class;

3.8 When I see ps.execute() ; , there is nothing to see after that is the way to execute sql through stmt in jdk. The key here is what the connection in stmt is;

Four: Important steps in the integration process with Spring

1. Configured org.mybatis.spring.SqlSessionFactoryBean . By default, its internal transactionFactory property is the SpringManagedTransactionFactory object (if you don't want Spring to manage transactions, you can actively specify the transactionFactory of sqlSessionFactoryBean as another class);

2. The transactionFactory object is saved as the SpringManagedTransactionFactory object in the sqlSessionFactory configuration environment of the SqlSessionFactoryBean. This step is very important;

3. Let's look at the openSessionFromDataSource method of DefaultSqlSessionFactory (where the sqlSession object is actually obtained), which contains the code

Environment environment = this.configuration.getEnvironment();
            TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
            tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
            Executor executor = this.configuration.newExecutor(tx, execType);
            var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);

Note: execType corresponds to SimpleExecutor by default, and the SpringManagedTransaction object generated by SpringManagedTransactionFactory is stored in this executor. Let’s make it clear here first;

4. The above has made it clear that the sqlSession execution statement is delegated to be executed by the exector; the following steps are consistent with those in the three mileage and will not be repeated;

Five: Important classes and methods of transaction management in Spring

1. org.springframework.transaction.interceptor.TransactionInterceptor , extremely important, this is when the pointcut method is executed, the transaction interceptor will do some additional processing according to the propagation configured by < tx :attributes> (it is a workaround), including whether You need to generate a connection object and set the value of the autoCommit of this connection object ( this.openConnection() of SpringManagedTransaction ; this value will be used ), for example, REQUIRED will first determine whether there is a connectionholder in the threadlocalmap, if there is no preprocessing, it will pass datasource gets the connection and sets autoCommit to false, then passes

connectionholer wraps this connection and sets it to threalocalmap;

2. org.springframework.jdbc.datasource.DataSourceTransactionManager , extremely important, is an important component used by spring to execute different logic according to the propagation strategy (executed in the invoke method of TransactionInterceptor);

3. TxNamespaceHandler is used to process elements whose namespace is tx;

4. TxAdviceBeanDefinitionParser is used to parse the <tx:advice element, which is processed by doParse;

5. NameMatchTransactionAttributeSource, extremely important, stores the strategy configured in <tx:attributes for TransactionInterceptor to use;

Supplement: If you want to understand spring's transaction management, you can start from the implementation of the invoke method of TransactionInterceptor. This is the entry function, and the ConnectionHolder used internally is a class that interacts with Mybatis;

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324727216&siteId=291194637