The problem and solution of ineffective calls in @Transactional transaction class

@Transactional internal call example

Under Spring's AOP proxy, the target method is managed by the proxy object generated by Spring only if the target method is invoked from the outside, which will cause self-invocation problems.
If other methods in the same class without the @Transactional annotation internally call the method with the @Transactional annotation, the transaction of the method with the @Transactional annotation will be ignored, and no rollback will occur

@Service

public class A{

   

  public void action(){

    dosome();

  }

   

  @Transactional

  public void dosome(){

    doa.insert(new Object());

  }

}


The solution is as in the above code, when an exception is thrown in the method dosome(), the data operation will not be rolled back

Idea: Force the use of AspectJ to cut the method

Springboot introduces AspectJ aspects

Add AspectJ in pom.xml:

<dependency>

  <groupId>org.springframework.boot</groupId>

  <artifactId>spring-boot-starter-aop</artifactId>

</dependency>

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->

<dependency>

  <groupId>org.aspectj</groupId>

  <artifactId>aspectjweaver</artifactId>

  <version>1.9.5</version>

</dependency>

Add @EnableAspectJAutoProxy(exposeProxy = true) to the startup class

@SpringBootApplication

@EnableAspectJAutoProxy(exposeProxy = true)

public class DonngPartsApplication {



  public static void main(String[] args) {

    SpringApplication.run(DonngPartsApplication.class, args);

  }



}

java.lang.IllegalStateException: Note: exposeProxy = true If not added, it will report:

Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available,

and ensure that AopContext.currentProxy() is invoked in the same thread as the AOP invocation context.

In the code ((A) AopContext.currentProxy()).dosome()

Modify it to the following code, and the transaction will take effect

@Service

public class A{

   

  public void action(){

    ((A) AopContext.currentProxy()).dosome();

  }

   

  @Transactional

  public void dosome(){

    doa.insert(new Object());

  }

}


1. Attribute information of @Transactional annotation @Transactional advanced

Attributes describe
name When there are multiple TransactionManagers in the configuration file, you can use this property to specify which transaction manager to choose
propagation Transaction propagation behavior, the default value is REQUIRED
isolation Transaction isolation, the default value is DEFAULT
timeout Transaction timeout, the default value is -1. Automatically rollback the transaction if the time limit is exceeded but the transaction has not yet completed
read-only Specifies whether the transaction is a read-only transaction, the default value is false; in order to ignore those methods that do not require transactions, such as reading data, you can set read-only to true
rollback-for It is used to specify the exception types that can trigger transaction rollback. If multiple exception types need to be specified, each type can be separated by commas
no-rollback- for Throw the exception type specified by no-rollback-for, do not roll back the transaction

2. propagation behavior

  • REQUIRED: If there is a transaction, then join the transaction, if not, create a new one (by default)
  • NOT_SUPPORTED: The container does not open a transaction for this method
  • REQUIRES_NEW: Regardless of whether there is a transaction, a new transaction is created, the original is suspended, the new execution is completed, and the old transaction is continued
  • MANDATORY: must be executed in an existing transaction, otherwise an exception will be thrown
  • NEVER: must be executed in a transaction that does not exist, otherwise an exception is thrown (opposite to MANDATORY)
  • SUPPORTS: If other beans call this method and declare transactions in other beans, then use transactions. If other beans do not declare transactions, then do not use transactions.
  • NESTED: Execute within a nested transaction if a transaction currently exists. If there is no transaction currently, perform a similar operation to PROPAGATION_REQUIRED.

3. Transaction timeout setting
@Transactional(timeout=30) //The default is 30 seconds

4. Transaction isolation level isolation

  • READ_UNCOMMITTED: Read uncommitted data (dirty reads, non-repeatable reads) are basically not used
  • READ_COMMITTED: Read committed data (non-repeatable reads and phantom reads will occur)
  • REPEATABLE_READ: Repeatable reading (phantom reading will occur)
  • SERIALIZABLE: serialization

Notice

@Transactional can only be applied to public methods

Just the presence of the @Transactional annotation is not enough to enable transactional behavior, it is just a kind of metadata

REQUIRED: If a transaction exists, the current transaction is supported. If there is no transaction, start a new transaction. REPEATABLE_READ: This transaction isolation level prevents dirty reads and non-repeatable reads. However, phantom reads may occur. In addition to ensuring that one transaction cannot read uncommitted data of another transaction, it also ensures that the following situations are avoided (non-repeatable read)

readOnly: No read-only rollbackFor: The rollback strategy is Exception TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); When an exception is caught in the function, it is necessary to set the transaction rollback status

Spring Transactional has always been the transaction artifact of RD, but if it is not used well, it will hurt yourself.

The following summarizes several scenarios that @Transactional often encounters:

@Transactional added to private method, invalid

@Transactional is added to the public method that has not been added to the interface, and then called through the ordinary interface method, it is invalid

@Transactional is added to the interface method, regardless of whether the private or public method is called below, it is valid

After @Transactional is added to the interface method, it is directly called by the ordinary interface method of this class, which is invalid

After @Transactional is added to the interface method, it is called by the common interface method of this class through the interface, which is valid

After @Transactional is added to the interface method, it is called by the interface method of its class, which is valid

After @Transactional is added to an interface method, it is valid after being called by a private method of its class 

Guess you like

Origin blog.csdn.net/LiZhen314/article/details/130603599