Detailed explanation of Spring transaction propagation behavior

Posted by sri.sjc on Wed, 09 Feb 2022 00:37:18 +0100

https://www.cnblogs.com/alimayun/p/10933289.html

Detailed explanation of Spring transaction propagation behavior
	</h2>
	<div id="cnblogs_post_body" class="blogpost-body blogpost-body-html">

preface

Spring specifies seven types of transaction propagation behaviors in the TransactionDefinition interface. Transaction propagation behavior is a unique transaction enhancement feature of spring framework. It does not belong to the database behavior of the actual transaction provider. This is a powerful toolkit provided by spring. Using the transaction propagation line can provide us with many conveniences for our development work. However, there are many misunderstandings about him. You must have heard the rumor that "service method transactions had better not be nested". To use tools correctly, you first need to understand the tools. This paper introduces seven transaction propagation behaviors in detail, which are mainly presented in the form of code examples.

Basic concepts

1. What is transaction propagation behavior?

Transaction propagation behavior is used to describe how a transaction propagates when a method modified by one transaction propagation behavior is nested into another method.

Description with pseudo code:

 public void methodA(){
    methodB();
    //doSomething
 }

@Transaction(Propagation=XXX)
public void methodB(){
//doSomething
}

The methodA() method in the code calls the methodB() method nested. The transaction propagation behavior of methodB() is determined by the @ Transaction(Propagation=XXX) setting. It is important to note that methodA() does not open transactions, and the method of modifying one transaction propagation behavior is not required to be invoked in the peripheral method of opening transactions.

2. Seven transaction propagation behaviors in Spring

Transaction propagation behavior typeexplain
PROPAGATION_REQUIREDIf there is no current transaction, create a new transaction. If there is already a transaction, join it. This is the most common choice.
PROPAGATION_SUPPORTSThe current transaction is supported. If there is no current transaction, it will be executed in a non transaction manner.
PROPAGATION_MANDATORYUse the current transaction. If there is no current transaction, throw an exception.
PROPAGATION_REQUIRES_NEWCreate a new transaction. If there is a current transaction, suspend the current transaction.
PROPAGATION_NOT_SUPPORTEDPerform operations in a non transactional manner. If there is a transaction currently, suspend the current transaction.
PROPAGATION_NEVERExecute in a non transactional manner. If there is a transaction currently, an exception will be thrown.
PROPAGATION_NESTEDIf a transaction currently exists, it is executed within a nested transaction. If there is no current transaction, execute the same as the deployment_ Required similar operations.

The definition is very simple and easy to understand. Let's go to the code test section to verify whether our understanding is correct.

Code verification

The code in this paper is presented in two layers of the traditional three-tier structure, namely Service layer and Dao layer. Spring is responsible for dependency injection and annotated transaction management. The Dao layer is implemented by Mybatis. You can also use any way you like, such as hibernate, JPA, JDBC template, etc. The database uses MySQL database. You can also use any database that supports transactions without affecting the verification results.

First, we create two tables in the database:

user1

CREATE TABLE `user1` (
  `id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(45) NOT NULL DEFAULT '',
  PRIMARY KEY(`id`)
)
ENGINE = InnoDB;

user2

CREATE TABLE `user2` (
  `id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(45) NOT NULL DEFAULT '',
  PRIMARY KEY(`id`)
)
ENGINE = InnoDB;

Then write the corresponding Bean and DAO layer code:

User1

public class User1 {
    private Integer id;
    private String name;
   //get and set methods omitted
}

User2

public class User2 {
    private Integer id;
    private String name;
   //get and set methods omitted
}

User1Mapper

public interface User1Mapper {
    int insert(User1 record);
    User1 selectByPrimaryKey(Integer id);
    //Other methods omit
}

User2Mapper

public interface User2Mapper {
    int insert(User2 record);
    User2 selectByPrimaryKey(Integer id);
    //Other methods omit
}

Finally, the specific verification code is implemented by the service layer, which is listed below.

1,PROPAGATION_REQUIRED

We add propagation to the corresponding methods of User1Service and User2Service Required attribute.

User1Service method:

@Service
public class User1ServiceImpl implements User1Service {
    //Omit other
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void addRequired(User1 user){
        user1Mapper.insert(user);
    }
}

User2Service method:

@Service
public class User2ServiceImpl implements User2Service {
    //Omit other
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void addRequired(User2 user){
        user2Mapper.insert(user);
    }
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void addRequiredException(User2 user){
        user2Mapper.insert(user);
        throw new RuntimeException();
    }

}

1.1 scenario I

The peripheral method of this scenario does not start a transaction.

Verification method 1:

 @Override
    public void notransaction_exception_required_required(){
        User1 user1=new User1();
        user1.setName("Zhang San");
        user1Service.addRequired(user1);
    User2 user2</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> User2();
    user2.setName(</span>"Li Si"<span style="color: rgba(0, 0, 0, 1)">);
    user2Service.addRequired(user2);
    
    </span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> RuntimeException();
}</span></pre>

Verification method 2:

@Override
    public void notransaction_required_required_exception(){
        User1 user1=new User1();
        user1.setName("Zhang San");
        user1Service.addRequired(user1);
    User2 user2</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> User2();
    user2.setName(</span>"Li Si"<span style="color: rgba(0, 0, 0, 1)">);
    user2Service.addRequiredException(user2);
}</span></pre>

Execute the verification method respectively, and the results are as follows:

Verification method serial numberDatabase resultsResult analysis
1"Zhang San" and "Li Si" are inserted.The peripheral method does not start the transaction, and the inserted "Zhang San" and "Li Si" methods run independently in their own transaction. The exception of the peripheral method does not affect the independent transaction of the internal inserted "Zhang San" and "Li Si" methods.
2"Zhang San" is inserted and "Li Si" is not inserted.The peripheral method has no transaction, and the insertion of "Zhang San" and "Li Si" methods run independently in their own transaction, so the exception thrown by the insertion of "Li Si" method will only roll back the insertion of "Li Si" method, and the insertion of "Zhang San" method will not be affected.

Conclusion: through these two methods, we have proved that propagation. When the peripheral method does not start the transaction The internal method modified by required will newly open its own transactions, and the opened transactions are independent of each other and do not interfere with each other.

1.2 scenario II

Peripheral methods start transactions. This is a scenario with high utilization.

Verification method 1:

@Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void transaction_exception_required_required(){
        User1 user1=new User1();
        user1.setName("Zhang San");
        user1Service.addRequired(user1);
    User2 user2</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> User2();
    user2.setName(</span>"Li Si"<span style="color: rgba(0, 0, 0, 1)">);
    user2Service.addRequired(user2);
    
    </span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> RuntimeException();
}</span></pre>

Verification method 2:

 @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void transaction_required_required_exception(){
        User1 user1=new User1();
        user1.setName("Zhang San");
        user1Service.addRequired(user1);
    User2 user2</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> User2();
    user2.setName(</span>"Li Si"<span style="color: rgba(0, 0, 0, 1)">);
    user2Service.addRequiredException(user2);
}</span></pre>

Verification method 3:

 @Transactional
    @Override
    public void transaction_required_required_exception_try(){
        User1 user1=new User1();
        user1.setName("Zhang San");
        user1Service.addRequired(user1);
    User2 user2</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> User2();
    user2.setName(</span>"Li Si"<span style="color: rgba(0, 0, 0, 1)">);
    </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
        user2Service.addRequiredException(user2);
    } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e) {
        System.out.println(</span>"Method rollback"<span style="color: rgba(0, 0, 0, 1)">);
    }
}</span></pre>

Execute the verification method respectively, and the results are as follows:

Verification method serial numberDatabase resultsResult analysis
1"Zhang San" and "Li Si" are not inserted.The peripheral method starts the transaction, the internal method joins the peripheral method transaction, the peripheral method rolls back, and the internal method also rolls back.
2"Zhang San" and "Li Si" are not inserted.The peripheral method starts the transaction, the internal method joins the peripheral method transaction, the internal method throws an exception and rolls back, and the peripheral method senses the exception, causing the overall transaction to roll back.
3"Zhang San" and "Li Si" are not inserted.The peripheral method starts the transaction, the internal method joins the peripheral method transaction, and the internal method throws an exception rollback. Even if the method is caught and not perceived by the peripheral method, the whole transaction is still rolled back.

Conclusion: the above test results show that when the peripheral method starts the transaction, propagation The internal method modified by required will be added to the transaction of the peripheral method, and all propagation The internal method and peripheral method modified by required belong to the same transaction. As long as one method is rolled back, the whole transaction is rolled back.

2,PROPAGATION_REQUIRES_NEW

We add propagation to the corresponding methods of User1Service and User2Service REQUIRES_ New property.
User1Service method:

 

@Service
public class User1ServiceImpl implements User1Service {
    //Omit other
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void addRequiresNew(User1 user){
        user1Mapper.insert(user);
    }
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void addRequired(User1 user){
        user1Mapper.insert(user);
    }
}

User2Service method:

@Service
public class User2ServiceImpl implements User2Service {
    //Omit other
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void addRequiresNew(User2 user){
        user2Mapper.insert(user);
    }
@Override
@Transactional(propagation </span>=<span style="color: rgba(0, 0, 0, 1)"> Propagation.REQUIRES_NEW)
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> addRequiresNewException(User2 user){
    user2Mapper.insert(user);
    </span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> RuntimeException();
}

}

2. 1 scenario I

The peripheral method did not open a transaction.

Verification method 1:

@Override
    public void notransaction_exception_requiresNew_requiresNew(){
        User1 user1=new User1();
        user1.setName("Zhang San");
        user1Service.addRequiresNew(user1);
    User2 user2</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> User2();
    user2.setName(</span>"Li Si"<span style="color: rgba(0, 0, 0, 1)">);
    user2Service.addRequiresNew(user2);
    </span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> RuntimeException();
    
}</span></pre>

Verification method 2:

@Override
    public void notransaction_requiresNew_requiresNew_exception(){
        User1 user1=new User1();
        user1.setName("Zhang San");
        user1Service.addRequiresNew(user1);
    User2 user2</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> User2();
    user2.setName(</span>"Li Si"<span style="color: rgba(0, 0, 0, 1)">);
    user2Service.addRequiresNewException(user2);
}</span></pre>

Execute the verification method respectively, and the results are as follows:

Verification method serial numberDatabase resultsResult analysis
1Insert "Zhang San" and "Li Si".There is no transaction in the peripheral method. The methods of "Zhang San" and "Li Si" are inserted and run independently in their own transactions. The exception rollback thrown by the peripheral method will not affect the internal method.
2"Zhang San" is inserted and "Li Si" is not insertedThe peripheral method does not start the transaction. Insert the "Zhang San" method and the "Li Si" method to start their own transactions respectively. Insert the "Li Si" method to throw an exception rollback, and other transactions will not be affected.

Conclusion: through these two methods, we have proved that propagation. When the peripheral method does not start the transaction REQUIRES_ The internal method modified by new will newly open its own transactions, and the opened transactions are independent of each other and do not interfere with each other.

2. 2 scenario II

The peripheral method starts the transaction.

Verification method 1:

@Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void transaction_exception_required_requiresNew_requiresNew(){
        User1 user1=new User1();
        user1.setName("Zhang San");
        user1Service.addRequired(user1);
    User2 user2</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> User2();
    user2.setName(</span>"Li Si"<span style="color: rgba(0, 0, 0, 1)">);
    user2Service.addRequiresNew(user2);
    
    User2 user3</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> User2();
    user3.setName(</span>"Wang Wu"<span style="color: rgba(0, 0, 0, 1)">);
    user2Service.addRequiresNew(user3);
    </span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> RuntimeException();
}</span></pre>

Verification method 2:

 @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void transaction_required_requiresNew_requiresNew_exception(){
        User1 user1=new User1();
        user1.setName("Zhang San");
        user1Service.addRequired(user1);
    User2 user2</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> User2();
    user2.setName(</span>"Li Si"<span style="color: rgba(0, 0, 0, 1)">);
    user2Service.addRequiresNew(user2);
    
    User2 user3</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> User2();
    user3.setName(</span>"Wang Wu"<span style="color: rgba(0, 0, 0, 1)">);
    user2Service.addRequiresNewException(user3);
}</span></pre>

Verification method 3:

@Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void transaction_required_requiresNew_requiresNew_exception_try(){
        User1 user1=new User1();
        user1.setName("Zhang San");
        user1Service.addRequired(user1);
    User2 user2</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> User2();
    user2.setName(</span>"Li Si"<span style="color: rgba(0, 0, 0, 1)">);
    user2Service.addRequiresNew(user2);
    User2 user3</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> User2();
    user3.setName(</span>"Wang Wu"<span style="color: rgba(0, 0, 0, 1)">);
    </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
        user2Service.addRequiresNewException(user3);
    } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e) {
        System.out.println(</span>"RollBACK "<span style="color: rgba(0, 0, 0, 1)">);
    }
}</span></pre>

Execute the verification method respectively, and the results are as follows:

Verification method serial numberDatabase resultsResult analysis
1"Zhang San" is not inserted, "Li Si" is inserted, "Wang Wu" is inserted.The peripheral method starts the transaction, inserts the "Zhang San" method and a transaction of the peripheral method, and inserts the "Li Si" method and the "Wang Wu" method. In the independent new transaction, the peripheral method throws an exception and only rolls back the method of the same transaction as the peripheral method, so the method of inserting "Zhang San" rolls back.
2"Zhang San" is not inserted, "Li Si" is inserted, "Wang Wu" is not inserted.The peripheral method starts the transaction, inserts the "Zhang San" method and the peripheral method into a transaction, and inserts the "Li Si" method and the "Wang Wu" method into the independent new transaction respectively. Inserting the "king five" method throws an exception. First, the transaction inserted into the "king five" method is rolled back. If the exception continues to be thrown, it is perceived by the peripheral method, and the peripheral method transaction is also rolled back. Therefore, inserting the "Zhang three" method is also rolled back.
3"Zhang San" is inserted, "Li Si" is inserted, "Wang Wu" is not inserted.The peripheral method starts the transaction, inserts the "Zhang San" method and the peripheral method into a transaction, and inserts the "Li Si" method and the "Wang Wu" method into the independent new transaction respectively. Inserting the "king five" method throws an exception. First, the transaction inserted into the "king five" method is rolled back. The exception is caught and will not be perceived by the peripheral method. The peripheral method transaction is not rolled back, so the "Zhang three" method is inserted successfully.

Conclusion: when the peripheral method starts the transaction, propagation REQUIRES_ The internal method modified by new will still open independent transactions, and is also independent of external method transactions. Internal methods, internal methods and external method transactions are independent of each other and do not interfere with each other.

3,PROPAGATION_NESTED

We add propagation to the corresponding methods of User1Service and User2Service Nested attribute.
User1Service method:

 

@Service
public class User1ServiceImpl implements User1Service {
    //Omit other
    @Override
    @Transactional(propagation = Propagation.NESTED)
    public void addNested(User1 user){
        user1Mapper.insert(user);
    }
}

User2Service method:

@Service
public class User2ServiceImpl implements User2Service {
    //Omit other
    @Override
    @Transactional(propagation = Propagation.NESTED)
    public void addNested(User2 user){
        user2Mapper.insert(user);
    }
@Override
@Transactional(propagation </span>=<span style="color: rgba(0, 0, 0, 1)"> Propagation.NESTED)
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> addNestedException(User2 user){
    user2Mapper.insert(user);
    </span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> RuntimeException();
}

}

3. 1 scenario I

The peripheral method of this scenario does not start a transaction.

Verification method 1:

@Override
    public void notransaction_exception_nested_nested(){
        User1 user1=new User1();
        user1.setName("Zhang San");
        user1Service.addNested(user1);
    User2 user2</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> User2();
    user2.setName(</span>"Li Si"<span style="color: rgba(0, 0, 0, 1)">);
    user2Service.addNested(user2);
    </span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> RuntimeException();
}</span></pre>

Verification method 2:

@Override
    public void notransaction_nested_nested_exception(){
        User1 user1=new User1();
        user1.setName("Zhang San");
        user1Service.addNested(user1);
    User2 user2</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> User2();
    user2.setName(</span>"Li Si"<span style="color: rgba(0, 0, 0, 1)">);
    user2Service.addNestedException(user2);
}</span></pre>

Execute the verification method respectively, and the results are as follows:

Verification method serial numberDatabase resultsResult analysis
1"Zhang San" and "Li Si" are inserted.The peripheral method does not start the transaction, and the inserted "Zhang San" and "Li Si" methods run independently in their own transaction. The exception of the peripheral method does not affect the independent transaction of the internal inserted "Zhang San" and "Li Si" methods.
2"Zhang San" is inserted and "Li Si" is not inserted.The peripheral method has no transaction, and the insertion of "Zhang San" and "Li Si" methods run independently in their own transaction, so the exception thrown by the insertion of "Li Si" method will only roll back the insertion of "Li Si" method, and the insertion of "Zhang San" method will not be affected.

Conclusion: through these two methods, we have proved that propagation. When the peripheral method does not start the transaction Nested and propagation The required function is the same. The modified internal methods will newly open their own transactions, and the opened transactions are independent and do not interfere with each other.

3.2 scenario II

The peripheral method starts the transaction.

Verification method 1:

@Transactional
    @Override
    public void transaction_exception_nested_nested(){
        User1 user1=new User1();
        user1.setName("Zhang San");
        user1Service.addNested(user1);
    User2 user2</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> User2();
    user2.setName(</span>"Li Si"<span style="color: rgba(0, 0, 0, 1)">);
    user2Service.addNested(user2);
    </span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> RuntimeException();
}</span></pre>

Verification method 2:

@Transactional
    @Override
    public void transaction_nested_nested_exception(){
        User1 user1=new User1();
        user1.setName("Zhang San");
        user1Service.addNested(user1);
    User2 user2</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> User2();
    user2.setName(</span>"Li Si"<span style="color: rgba(0, 0, 0, 1)">);
    user2Service.addNestedException(user2);
}</span></pre>

Verification method 3:

@Transactional
    @Override
    public void transaction_nested_nested_exception_try(){
        User1 user1=new User1();
        user1.setName("Zhang San");
        user1Service.addNested(user1);
    User2 user2</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> User2();
    user2.setName(</span>"Li Si"<span style="color: rgba(0, 0, 0, 1)">);
    </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
        user2Service.addNestedException(user2);
    } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e) {
        System.out.println(</span>"Method rollback"<span style="color: rgba(0, 0, 0, 1)">);
    }
}</span></pre>

Execute the verification method respectively, and the results are as follows:

Verification method serial numberDatabase resultsResult analysis
1"Zhang San" and "Li Si" are not inserted.The peripheral method starts the transaction, and the internal transaction is the sub transaction of the peripheral transaction. The peripheral method rolls back, and the internal method also rolls back.
2"Zhang San" and "Li Si" are not inserted.The peripheral method starts the transaction. The internal transaction is a sub transaction of the peripheral transaction. The internal method throws an exception and rolls back, and the peripheral method perceives the exception, resulting in the rollback of the overall transaction.
3"Zhang San" is inserted and "Li Si" is not inserted.The external method starts the transaction, and the internal transaction is the sub transaction of the external transaction. Insert the "Zhang San" internal method to throw an exception, and the sub transaction can be rolled back separately.

Conclusion: the above test results show that when the peripheral method starts the transaction, propagation The internal method modified by nested belongs to the sub transaction of external transaction. The peripheral main transaction is rolled back, and the sub transaction must be rolled back, while the internal sub transaction can be rolled back separately without affecting the peripheral main transaction and other sub transactions

4.,REQUIRED,REQUIRES_ Similarities and differences between new and nested

From the comparison between "1.2 scenario II" and "3.2 scenario II", we can see:
The internal methods modified by needed and REQUIRED belong to peripheral method transactions. If the peripheral method throws an exception, the transactions of both methods will be rolled back. However, REQUIRED is to join the peripheral method transaction, so it belongs to the same transaction as the peripheral transaction. Once the REQUIRED transaction throws an exception and is rolled back, the peripheral method transaction will also be rolled back. The NESTED method is a sub transaction of the peripheral method and has a separate savepoint, so the exception thrown by the NESTED method is rolled back and will not affect the transaction of the peripheral method.

From the comparison between "2.2 scenario II" and "3.2 scenario II", we can see:
NESTED and requirements_ New can roll back internal method transactions without affecting peripheral method transactions. However, because NESTED transactions are NESTED transactions, after the peripheral method is rolled back, the sub transactions as peripheral method transactions will also be rolled back. And requirements_ New is realized by opening new transactions. Internal transactions and peripheral transactions are two transactions. The rollback of peripheral transactions will not affect internal transactions.

Simulation use case

After introducing so many transaction propagation behaviors, how can we apply them in practical work? Let me give an example:

Suppose we have a registration method. We call the method of adding the integral. If we want to add the integral, it will not affect the registration process (that is, adding the integral execution failure roll back can not make the registration method rollback).

@Service
   public class UserServiceImpl implements UserService {
    @Transactional
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> register(User user){
               
        </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
            membershipPointService.addPoint(Point point);
        } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e) {
           </span><span style="color: rgba(0, 128, 0, 1)">//< / span > < span style = "color: RGBA (0, 128, 0, 1)" > omit</ span>

}
//Omit
}
//Omit
}

We also stipulate that the registration failure will affect the addPoint() method (the registration method needs to be rolled back and the integral adding method also needs to be rolled back), so the addPoint() method needs to be implemented in this way:

@Service
   public class MembershipPointServiceImpl implements MembershipPointService{
    @Transactional(propagation </span>=<span style="color: rgba(0, 0, 0, 1)"> Propagation.NESTED)
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> addPoint(Point point){
               
        </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
            recordService.addRecord(Record record);
        } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e) {
           </span><span style="color: rgba(0, 128, 0, 1)">//< / span > < span style = "color: RGBA (0, 128, 0, 1)" > omit</ span>

}
//Omit
}
//Omit
}

We noticed that addRecord() method is also called in addPoint(), which is used to record logs. His achievements are as follows:

@Service
   public class RecordServiceImpl implements RecordService{
    @Transactional(propagation </span>=<span style="color: rgba(0, 0, 0, 1)"> Propagation.NOT_SUPPORTED)
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> addRecord(Record record){
               
       
        </span><span style="color: rgba(0, 128, 0, 1)">//< / span > < span style = "color: RGBA (0, 128, 0, 1)" > omit</ span>

}
//Omit
}

We notice that propagation = propagation in the addRecord() method NOT_ Supported, because it doesn't care about the accuracy of the log, you can have one more or one less, so the exception thrown by the addRecord() method itself and the peripheral addPoint() method will not roll back the addRecord() method, and the exception thrown by the addRecord() method will not affect the execution of the peripheral addPoint() method.

Through this example, I believe you have a more intuitive understanding of the use of transaction propagation behavior. The combination of various attributes can really make our business implementation more flexible and diverse.

 

 
If you want to give me more encouragement, Beg to fight

Because my writing enthusiasm is inseparable from your positive support. Thank you for reading. I am [Alibaba cloud Ma]!

Classification: spring foundation
<div id="blog_post_info">
+Pay more attention
6
0
<div class="clear"></div>
<div id="post_next_prev">

<a href="https://www.cnblogs. com/alimayun/p/10933076. html" class="p_ n_ p_ Prefix "> previous: < a href =" " https://www.cnblogs.com/alimayun/p/10933076.html "Title =" published at 20:44, May 27, 2019 "> java concurrency series (VII) -- principle analysis of ConcurrentHashMap (JDK1.8)</a>
<br>
<a href="https://www.cnblogs. com/alimayun/p/10934202. html" class="p_ n_ p_ Prefix "> » < / a > next: < a href =" " https://www.cnblogs.com/alimayun/p/10934202.html "Title =" released at 23:12, May 27, 2019 "> java Concurrent series (VIII) -- java asynchronous programming</a>

posted on 2019-05-27 21:07  Study notes of Ali Ma Yun Reading (2915) comments (2) edit Collect

Refresh page Back to top
You can't view or comment until you're signed in. Now perhaps Stroll Blog Garden Home Page
[recommended] HBase+Lindrom, big data application practice, Internet of things data decryption
[recommended] 500000 lines of VC + + source code for large-scale configuration, industrial control, simulation, CAD \ GIS are downloaded for free!
[recommended] 100 Beta beta Beta places for HarmonyOS 2.0 developers, claimed within a limited time!
[recommendation] Alibaba cloud's sales list of explosive products is released, and the selected explosive products are as low as 0.55% off
[recommended] second kill! National cloud big data magic mirror, enterprise level cloud analysis platform

Topics: Spring