Propagation of Spring Transaction Properties

Source: http://blog.csdn.net/kiwi_coder/article/details/20214939
Comments:
There is a very important attribute in Spring Transaction: Propagation. It is mainly used to configure the relationship between the method that needs to be executed and whether there is currently a transaction.

I know it's a bit abstract, which is why I wanted to write this blog. After reading the following example, everyone should understand.


1. Propagation value:

REQUIRED (default value): execute in the state of transaction; if there is no transaction, create a new transaction;

SUPPORTS: if there is a transaction, execute in the state of transaction; if there is no transaction, in Execute in no transaction state;

MANDATORY: must be executed in a transaction state, if there is no current transaction, an exception IllegalTransactionStateException is thrown;

REQUIRES_NEW: Create a new transaction and execute it; if there is a current transaction, suspend the current transaction;

NOT_SUPPORTED : Execute in no transaction state; if there is a current transaction, suspend the current transaction;

NEVER: Execute in no transaction state; if there is a current transaction, throw an exception IllegalTransactionStateException.


2. REQUIRED and REQUIRED_NEW

Among the six types of propagation attribute configurations described above, the most difficult to understand and prone to problems in transaction design is the difference between REQUIRED and REQUIRED_NEW. When a program throws an exception under certain circumstances, it may be difficult to spot and fix the problem if you don't know enough about both.


Below we give three scenarios for analysis:

Scenario 1:

ServiceA.java:

public class ServiceA {
    @Transactional
    public void callB() {
        serviceB.doSomething();
    }
}

ServiceB.java

public class ServiceB {
    @Transactional
    public void doSomething( ) {
        throw new RuntimeException("B throw exception");
    }
}
In this case, we only need to catch the runtime exception thrown in ServiceB when calling ServiceA.callB, then the transaction will rollback normally.


Scenario 2 Keep ServiceB unchanged

in scenario 1, and catch this exception when calling doSomething of ServiceB in ServiceA, as follows:

public class ServiceA {
    @Transactional
    public void callB() {
        try {
            serviceB.doSomething();
        } catch (RuntimeException e) {
            System.err.println(e.getMessage());
        }
    }
}
At this time, we call ServiceA again callB. The program will throw an exception message like org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only. what is the reason?

Because @Transactional propagation in ServiceA and ServiceB adopts the default value: REQUREID. According to the REQUIRED feature we talked about earlier, when ServiceA calls ServiceB, they are in the same transaction. As shown below:


When an exception is thrown in ServiceB, ServiceB will mark the current transaction as requiring rollback. But ServiceA caught this exception and processed it, thinking that the current transaction should be committed normally. At this point, there is inconsistency, and because of this, the previous UnexpectedRollbackException is thrown.


Scenario 3 Keeping ServiceA unchanged

in scenario 2, modify the propagation configuration of the method in ServiceB to REQUIRES_NEW, as follows:

public class ServiceB {
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void doSomething() {
        throw new RuntimeException("B throw exception ");
    }
}
At this point, the program can exit normally without throwing UnexpectedRollbackException. The reason is because when ServiceA calls ServiceB, serviceB's doSomething is executed in a new transaction. As shown in the following figure:


Therefore, when doSomething throws an exception, it just rolls back the newly created transaction, without affecting the transaction of ServiceA. ServiceA can commit normally.

Of course, if ServiceA and ServiceB are placed in two separate transactions, you need to consider your business needs more.


Transaction is not a new thing, so will there be some patterns for the use of transaction? What about some experience? The answer is definitely yes, and I will talk about it later in the blog.


Reference: Spring Transaction Propagation

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=327034182&siteId=291194637