@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