1. Overview
Spring's transaction annotations @transaction believe that many people have used it, while the @transaction default configuration is appropriate for the 80% configuration.
This article does not describe the spring annotation transaction in detail, but rather addresses some of the problems encountered in the actual scenario
2. Transaction ROLLBACK 2.1 Default Rollback policy
@Transactionalpublic void Rollback () throws SQLException { //update db throw new SQLException ("Exception");}
Will the above code transaction be rolled back? No, even if the SqlException is thrown, the previous database operation is still committed, because @transactional only runtimeexception and error are rolled back by default.
2.2 Specifying ROLLBACK exceptions
Therefore, if you want to specify which exceptions need to be rolled back, configure @transactional in Rollbackfor, for example
@Transactional (rollbackfor = {sqlexception.class}) public void rollback () throws SQLException { //update DB throw new SQLException ("Exception");}
According to the above example, the specified SqlException, when the runtimeexception is thrown, will it be rolled back?
@Transactional (rollbackfor = {sqlexception.class}) public void rollback () throws SQLException { //update DB throw new Runtime ("Exception");}
It's still going to roll back.
2.3 Transaction Nesting Rollback
Assuming the following logic, the transaction rolls back (or Updatea,updateb,updatec) which updates are committed
@Transactionalpublic void rollback () { //UpdateA try{ inneltransaction () }catch (runtimeexception E { //do nothing } //updatec} @Transactionalpublic void Inneltransaction () throws SQLException { // Updateb throw new RuntimeException ("Exception");}
The answer is to commit, because the matching rules for the rollback of a transaction are nested to the outermost, whichever is the following code.
@Transactionalpublic void Rollback () throws sqlexception{ //UpdateA inneltransaction () //updatec} @ Transactional (rollbackfor = sqlexception.class) public void Inneltransaction () throws SQLException { //Updateb throw new SQLException ("Exception");}
UpdateA and Updateb will still be submitted, Updatec will not commit (because the code does not execute here)
2.4 Summary
Therefore, when a transaction rollback is required, it is best to throw runtimeexception and do not catch such exceptions in the code
Third, the dissemination of business
The propagation of the @Transaction can be configured with the spread of the transaction, the online introduction of many, directly copied a paragraph
PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 (也是默认策略)PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。 PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。 PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。 PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。
3.1 How to read the latest configuration in a transaction
Sometimes it is necessary to read the most recent data in one transaction (the default is to read the snapshot before the transaction begins). In fact, it is very simple, as long as the use of the above propagation_not_supported dissemination.
@Transactionalpublic void Transaction () throws SQLException { //do something querynewvalue ();} @Transactional (propagation = propagation.not_supported) public void Querynewvalue () throws SQLException { //Query the latest value in data}
You think the above can take effect, it is wrong to call the transaction method in the same class, cannot be directly called.
Iv. internal invocation of transaction methods
The essence of a transaction annotation is to create a dynamic proxy that opens a transaction before the transaction method is invoked, deciding whether to commit the transaction or rollback after the transaction method ends.
Therefore, invoking the transaction method directly within the class is not a dynamic proxy
。 Therefore, if you want the method B point transaction to take effect, you must do so
4.1 Solutions
WORKAROUND: When you call method B internally, find the proxy class for the current class, and use the proxy class to call method B
4.1.1 Solution 1
@Servicepublic class myservice{ @Transactional public Void Transaction () { //do Something ( ( MyService) Aopcontext.currentproxy ()). Querynewvalue (); } @Transactional (propagation = propagation.not_supported) public void Querynewvalue () { //Query the latest value in Data }}
You can get the proxy class for the current class by Aopcontext.currentproxy (), but to use this time, you must add the
@EnableAspectJAutoProxy (Exposeproxy=true)
4.1.2 Solution 2
Since it is to get the current proxy class, it is actually directly in the spring container inside to get also can ah. There are roughly 2 ways to fetch beans in spring.
by injecting
@Servicepublic class myservice{ @Autowired private myservice self; @Transactional public Void Transaction () { //do something self.querynewvalue (); } @Transactional (propagation = propagation.not_supported) public void Querynewvalue () { //Query the latest value in Data }}
Tips:spring now provides support for some circular dependencies, simply to satisfy:
- Bean is a singleton
- Injected in a way that is not a constructor injection
by beanfactory
@Servicepublic class MyService implements beanfactoryaware{ private myservice self; @Transactional public Void Transaction () { //do something self.querynewvalue (); } @Transactional (propagation = propagation.not_supported) public void Querynewvalue () { //Query the latest value in data } @Override public void Setbeanfactory (Beanfactory beanfactory) throws beansexception {Self = Beanfactory.getbean (Myservice.class); }}
Although the previous method is feasible in most cases, there are cases where cyclic dependencies are reported (try to have @transaction and @async in the Class). Instead of relying on spring to resolve circular dependencies, use Beanfactoryaware to inject, which is set after the bean is initially completed.
4.2 Places to be aware of
- Methods that use @transaction annotations must be decorated with public.
- In fact, not only @transaction, other similar @cacheable, @Retryable and other dependent spring proxy must also use the above method to achieve internal calls.
About Spring transaction Annotations combat