Article From:

Note a Spring transaction configuration trample

Description of the problem: (SpringBoot + MyBatis Plus)

The business logic pseudocode is as follows. In theory, after inserting data t1, the query conditions of the xxService. getXxx () method will not be satisfied and the data will not be queried. The result was contrary to expectation. The data was found in the last query.

void saveXxx(){
 xxService.getXxx(); // Find a data data1
 xxService.insert(); // Insert a data T1
 xxService.getXxx(); // Find a data data1


Analysis process:

Abandon business logic, write a simple test in a new service, query – & gt; insert – & gt; query. To ensure comparability, SQL is copied from the original Mapper. But the problem can’t be repeated.Amazingly, the following happened:

void testMyBatis(){
 yyService.getYyy(); // Find a data data1
 yyService.insert(); // Insert a data T1
 yyService.getYyy(); // No data available
 xxService.getXxx(); // Find a data data1

In theory, both yyyService. getYyy () and xxService. getXxx () should not be able to find the data. The result is only xxService. getXxx ().

Does xxService. getXxx () open a new transaction to query, so that the query condition of xxService. getXxx () is not affected by the data inserted by the current transaction?

Check the transaction configuration in the project. In addition to the annotated transaction configuration, there are the following declarative transaction configurations:

public TransactionInterceptor txAdvice() {
NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
RuleBasedTransactionAttribute readOnlyTx = new RuleBasedTransactionAttribute();
readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED );
RuleBasedTransactionAttribute requiredTx = new RuleBasedTransactionAttribute();
requiredTx.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
Map<String, TransactionAttribute> txMap = new HashMap<>();
txMap.put("add*", requiredTx);
txMap.put("save*", requiredTx);
txMap.put("insert*", requiredTx);
txMap.put("update*", requiredTx);
txMap.put("delete*", requiredTx);
txMap.put("get*", readOnlyTx);
txMap.put("query*", readOnlyTx);
source.setNameMap( txMap );
TransactionInterceptor txAdvice = new TransactionInterceptor(transactionManager, source);
return txAdvice;

That’s the trick of this configuration: readOnlyTx. setPropagation Behavior (Transaction Definition. PROPAGATION_NOT_SUPPORTED); get*At the beginning, read-only transactions are added, while read-only transactions run in a non-transactional manner. If there is a transaction, the current transaction is suspended.

This explains why the xxService. getXxx () method can look up data, which is queried outside the current transaction.


Attachment: Still use annotated transactions ^uuuuuuuuuuuuu

Leave a Reply

Your email address will not be published. Required fields are marked *