Attention problems using @Transactional

The basic principles outlined @Transactional

When the target application method declaration @Transactional system call, Spring Framework AOP proxy is used by default, generate a proxy object code runs, the configuration information based on the properties of @Transactional, the proxy object method to determine the target of the statement by the interceptor whether @Transactional is TransactionInterceptor to use interceptors, will be created when TransactionInterceptor interception before starting the target method and add transaction and perform logical target method, and finally is abnormal according to the implementation, use abstract transaction manager AbstractPlatformTransactionManager operational data sources DataSource submitted or roll back the transaction.

You need to pay attention to things

1. @ Transactional public can only be applied to the method for other non-public way, if marked @Transactional not an error, but the method is not transactional capabilities
recommendation is that you 2.Spring team in a specific category (or categories use @Transactional annotation on the method), rather than on any interface type to be achieved.
3. Of course, you can use @Transactional annotation on an interface, but this will only be when you set it to take effect when the agent interface-based. Because annotations are not inherited, which means that if you are using a proxy class-based, set the transaction will not be recognized based on the proxy class, and the object will not be the Acting packed (to be confirmed severe). Therefore, in the specific use or class notes @Transactional better.
4. To avoid self-call Spring's AOP problem: when calling from another is to call the method of the present class A plus transaction annotated Method B, Method B is the operation of the database without a transaction.

Under Spring AOP proxy, only the target method is called by an external, objective method was generated by the Spring proxy object to manage, which can cause problems since the call. If no other method of internal affairs @Transactional notes of the same class have to call @Transactional annotation methods have @Transactional annotation methods are ignored, the rollback does not occur.
Failure:
Here Insert Picture Description
Method one two methods are public:

classA, any method to invoke classB, spring is by way of proxy, then the spring annotations take effect
classA, the one method call methods within the same class of two, namely this call, spring annotation will not take effect (eg @Cachable , @ Transaction)

Solution

Option One: using AspectJ agent

@Service
public class OrderService {
    private void insert() {
        insertOrder();
    }
@Transactional
    public void insertOrder() {
        //insert log info
        //insertOrder
        //updateAccount
       }
}

insertOrder Despite @Transactional notes, but it is an internal insert method calls, the transaction is ignored, abnormal transaction rollback does not occur.

The above two issues @Transactional annotation methods and apply only to public calls from problems due to the use of Spring AOP proxy caused. In order to solve these two problems, you can use AspectJ replace Spring AOP proxy, but now there is a better solution.

Scheme 2: Using the AopContext.currentProxy () method to obtain Agent

Means method is to try to return the current AOP proxy. This approach is very simple, but by default does not work! Because AopContext get in currentProxy, it will be reported null pointer. Requires some additional configuration, but not to intercept all the comments are valid, because these notes are not used AspectJ agent, if it is @Transactional Affairs notes, it is in effect, the details to turn the source code, and is not recommended use.

Option Three: to obtain the dynamic proxy object through ApplicationContext (recommended)

@Component
public class AsyncService implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    public void async1() {
        System.out.println("1:" + Thread.currentThread().getName());
        // 使用AppicationContext来获得动态代理的bean,然后再执行你调用的方法
        this.applicationContext.getBean(AsyncService.class).async2();
    }

    @Async
    public void async2() {
        System.out.println("2:" + Thread.currentThread().getName());
    }

    // 注入ApplicationContext
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
Published 45 original articles · won praise 1 · views 1090

Guess you like

Origin blog.csdn.net/lqq404270201/article/details/103473848