Within a Service, nested calls between transactional methods, or between ordinary methods and transactional methods, do not start a new transaction. This is because Spring uses dynamic proxies for transaction control, and dynamic proxies end up calling primitive objects that no longer trigger proxies when they call methods!
First let’s look at the propagation mechanism and cause analysis of Spring transactions
PROPAGATION_REQUIRED
: Supports the current transaction. If there is no transaction, create a new one. This is the most common choicePROPAGATION_SUPPORTS
: Supports the current transaction, and if there is no transaction, it is executed nontransactionallyPROPAGATION_MANDATORY
: Supports the current transaction and throws an exception if there is no current transactionPROPAGATION_REQUIRES_NEW
: Creates a transaction and suspends the current transaction if one existsPROPAGATION_NOT_SUPPORTED
: Performs operations nontransactionally, suspending the current transaction if one existsPROPAGATION_NEVER
: Executes nontransactionally and throws an exception if a transaction currently existsPROPAGATION_NESTED
: Executes within a nested transaction if a transaction currently exists. If there are no transactions currently, an operation similar to PROPAGATION_REQUIRED is performed
Spring defaults to A PROPAGATION_REQUIRED mechanism. It’s okay for method A to annotate @Transactional, propagated to method B because method A opens A transaction, The connection property in the thread is autoCommit=false, and the transaction propagation is still in effect when method B is executed. The result is still the connection of method A, and the autoCommit is still false, so the transaction is in effect.
Otherwise, if method A does not annotate @Transactional, it is not Transactional, and autoCommit=true, then the propagation to method B is true, even if method B annotates @Transactional;
The solution
- Pull method B into another XXService, inject XXService into this Service, and call method B with XXService
- Method B is called through the proxy object by getting the current class proxy object inside the method
The dynamic proxy will eventually call the original object, and the original object will no longer trigger the proxy when it calls the method. 1. Use the ApplicationContext context object to get this object. 2. Use AopContext. CurrentProxy () gets the proxy object, but needs to configure exposeProxy=true springBoot boot class annotated: @enableAspectJAutoProxy (exposeProxy =true)Copy the code
Method gets the proxy object call method internally