@Transactional invalidation problem when different methods of the same kind call each other

This article aims to explore the impact of mutual method calls on the validity of Spring transaction annotations in the same class.

suppose

Class A has two methods, a and b:
method a is modified by public, and method b will be called when it is executed;
method b is modified by private, and it will operate on the database when it is executed.

Scenes

scene 1

Method a calls method b, method a has no transaction annotation decoration, at this time, no matter whether method b has transaction annotation decoration or not, the transaction will be invalid;

scene 2

Method a calls method b, and method a is decorated with transaction annotations, then the transaction of method a will take effect, and the exception thrown in method b will also be rolled back. At this time, if method b is decorated with transaction annotations, the transaction of method b will become invalid.

Cause Analysis

When calling methods of other classes from the outside, if the target method is modified with transaction annotation, then when spring scans the bean, it will generate a wrapped proxy class for the method containing @Transactional, and use AOP to start the transaction before the method is executed. Commit/rollback transactions after execution. However, the method calls between classes do not follow this logic, so there will be no proxy objects, and transactions will not be started.

Solution

  1. Add the transaction of the parent method: when method a in class A calls method b, annotations can be added to a to manage the common transactions of method a and method b.
  2. Use programmatic transactions in methods:
//引入事务模板
@Autowired
TransactionTemplate transactionTemplate;

//在b方法(被调方法)中使用模板创建并执行语句
transactionTemplate.execute((TransactionCallback<Void>) status -> {
    
    
	// 业务逻辑
	return null;
})
  1. Get the proxy object of the current class, use the proxy object to call the b method
    • Inject itself and use the injected object to call the b method
    • Get the current proxy class through the spring context, use the proxy class to call the b method
    • Use AopContext to get the current proxy class, use the proxy class to call b method

extension

The logic of method calls between different classes

Method a of class A calls method b of class B, as long as method a or b is configured with a transaction, the transaction will take effect at this time.
If both methods are configured with transactions, how the two transactions are propagated depends on the set transaction propagation characteristics. The default method of spring transactions is REQUIRED (join if there is a transaction, create if there is no transaction), in this case, if both methods a and b are annotated with @Transactional, because a calls b, then b method will be added to a method executed in the transaction.

spring transaction propagation feature

REQUIRED (Spring's default transaction propagation type required: need, depend on, depend on): If there is no transaction currently, create a new transaction yourself, if there is a transaction currently, join this transaction When A calls B: if there is no transaction in A,
B If there is a transaction in A, then B will create a new transaction; if there is a transaction in A, and there is a transaction in B, then B will join A and become a transaction. At this time, either all succeed or both fail. (If there are 2 SQLs in A and 2 SQLs in B, then these four SQLs will become one SQL, either all succeed or all fail)

SUPPORTS (supports: support; support): There is currently a transaction, then join the current transaction, if there is no transaction, it will be executed in a non-transactional method If there is a transaction
in A, then the transaction of the B method will be added to the A transaction to become a transaction (together success, failure together), if there is no transaction in A, then B will run in a non-transactional mode (commit directly after execution);

MANDATORY (mandatory: mandatory): If there is a current transaction, join the current transaction, and if the current transaction does not exist, an exception will be thrown.
If there is a transaction in A, the transaction of method B is added to the transaction of A to become a transaction (succeed together, fail together); if there is no transaction in A and there is a transaction in B, then B will directly throw an exception, which means that B must Run within a transaction to support rollback

REQUIRES_NEW (requires_new: requires new): Create a new transaction, if there is a current transaction, suspend the transaction.
B will create a new transaction, and A and B transactions will not interfere with each other. When they have problems and roll back, they will only roll back their own transactions;

NOT_SUPPORTED (not supported: not supported): Executed in a non-transactional manner. If there is a transaction currently, the
callee B will suspend the current transaction and run in a non-transactional manner (submit directly). Transaction, A will be suspended (not executed, wait for B to finish executing, return); A and B have an exception and need to roll back, without affecting each other

NEVER (never: never): If no transaction currently exists, it will be executed in a non-transactional manner; if there is, an exception will be thrown. That is, B never runs in a transactional manner.
A cannot have a transaction. If not, B will execute in a non-transactional manner. If A has a transaction, then an exception will be thrown directly.

NESTED (nested: nested) nested transaction: If the current transaction exists, it will be executed in the nested transaction, otherwise the operation of REQUIRED is the same (open a transaction)
If there is no transaction in A, then B creates a transaction to execute, if A There is also a transaction in it, then B will nest the transaction in it

reference article

https://blog.csdn.net/ChineseSoftware/article/details/127602310
https://blog.csdn.net/single_0910/article/details/121561725
https://blog.csdn.net/dayuiicghaid/article/details/125260092
https://blog.csdn.net/hellozhxy/article/details/109753711

Guess you like

Origin blog.csdn.net/Ka__ze/article/details/131087408