spring transaction properties

Spring declarative transactions free us from complex transaction processing. So that we no longer need to deal with obtaining connections, closing connections, transaction commits, and rollbacks. No longer do we need to deal with lots of try...catch...finally code in transaction related methods.
When we use Spring declarative transactions, a very important concept is transaction attributes. Transaction properties typically consist of the transaction's propagation behavior, the transaction's isolation level, the transaction's timeout value, and the transaction read-only flag. When we divide the transaction, we need to define the transaction, that is, configure the properties of the transaction.
Spring defines these properties in the TransactionDefinition interface for use by PlatfromTransactionManager, which is the core interface for spring transaction management.
Java code Collection code
TransactionDefinition 
public interface TransactionDefinition { 
    int getPropagationBehavior(); 
    int getIsolationLevel(); 
    int getTimeout(); 
    boolean isReadOnly(); 



getTimeout() method, which returns how many seconds the transaction must complete.
isReadOnly(), whether the transaction is read-only, the transaction manager can optimize based on this return value to ensure that the transaction is read-only.
The getIsolationLevel() method returns the isolation level of the transaction, according to which the transaction manager controls which data in this transaction can be seen by another transaction.

Five different transaction isolation levels are defined in the TransactionDefinition interface.
ISOLATION_DEFAULT This is the default isolation level of PlatfromTransactionManager, which uses the default transaction isolation level of the database. The other four correspond to the isolation level of JDBC.
ISOLATION_READ_UNCOMMITTED This is the lowest isolation level of transactions. It allows another transaction to see the uncommitted data of this transaction. This isolation level produces dirty reads, non-repeatable reads and phantom reads.
  For example:
  Mary's original salary was 1000, the financial staff changed Mary's salary to 8000, but the transaction
Java code was not submitted. Collection code
Connection con1 = getConnection(); 
con.setAutoCommit(false); 
update employee set salary = 8000 where empId = "Mary"; 

At the same time, Mary is reading her own salary
Java code Collection code
Connection con2 = getConnection(); 
select salary from employee where empId = "Mary"; 
con2.commit(); 


Mary finds that her salary has become 8000, rejoice!
The finance found that the operation was wrong, and the transaction was rolled  back   ,  and Mary's
salary became 1000 again . ISOLATION_READ_COMMITTED ensures that data modified by one transaction can only be read by another transaction after it is committed. Another transaction cannot read the transaction's uncommitted data. This transaction isolation level can avoid dirty reads, but non-repeatable reads and phantom reads may occur. ISOLATION_REPEATABLE_READ This transaction isolation level can prevent dirty reads and non-repeatable reads. However, phantom reads may occur. In addition to ensuring that a transaction cannot read uncommitted data of another transaction, it also ensures that the following situation (non-repeatable read) is avoided. In transaction 1, Mary read her own salary as 1000, and the operation did not complete the Java code Collection code con1 = getConnection();  select salary from employee empId = "Mary";  In transaction 2, the financial staff modified Mary's salary is 2000, and the transaction is submitted. Java code Collection code con2 = getConnection();  update employee set salary = 2000;  con2.commit();  In transaction 1, when Mary reads her own salary again, the salary changes For 2000 Java Code Favorite Code
























//con1 
select salary from employee empId = "Mary"; 


The results of two reads before and after one transaction are inconsistent, resulting in non-repeatable reads.
Use ISOLATION_REPEATABLE_READ to avoid this.

ISOLATION_SERIALIZABLE This is the most expensive but most reliable transaction isolation level. Transactions are processed for sequential execution. In addition to preventing dirty reads, non-repeatable reads, it also avoids phantom reads.

There are currently 10 employees with a salary of 1000.
Transaction 1, reads all employees whose salary is 1000.
Java code Collection code
con1 = getConnection(); 
Select * from employee where salary =1000; 
A total of 10 records are read

At this time another transaction inserts an employee record into the employee table, and the salary is also 1000
Java code Collection code
con2 = getConnection (); 
Insert into employee(empId,salary) values("Lili",1000); 
con2.commit(); 


Transaction 1 reads the
Java code of all employees whose salary is 1000 again. Collection code
//con1 
select * from employee where salary =1000; 


A total of 11 records were read, which resulted in a phantom read.
ISOLATION_SERIALIZABLE prevents this from happening. But this also consumes the most resources.

getPropagationBehavior() returns the propagation behavior of the transaction, determined by whether there is an active transaction for a transaction invocation.

Seven transaction propagation behaviors are defined in the TransactionDefinition interface.

PROPAGATION_REQUIRED If a transaction exists, the current transaction is supported. If there is no transaction, start a new transaction.

Java code Collection code
//Transaction property PROPAGATION_REQUIRED 
methodA{ 
…… 
methodB(); 
…… 

 
//Transaction property PROPAGATION_REQUIRED 
methodB{ 
   …… 


uses spring declarative transaction, spring uses AOP to support declarative transaction, according to the transaction attribute, Automatically decides whether to start a transaction before the method is called, and decides whether to commit or roll back the transaction after the method is executed.

Call methodB method
Java code alone, favorite code
main{ 
  metodB(); 


is equivalent to
Java code, favorite code
Main{ 
Connection con=null; 
 
   rry{ 
      con = getConnection(); 
      con.setAutoCommit(false); 
//method call 
methodB(); 
//commit transaction 
con.commit(); 

Catch(RuntimeException ex){ 
  //rollback transaction 
  con.rollback();   

finally{ 
  //Release resources 
  closeCon(); 



Spring guarantees that all calls in the methodB method get the same connection. At the time methodB is called, there is no existing transaction, so a new connection is obtained and a new transaction is started.

When MethodA is called alone, MethodB will be called in MethodA. The

execution effect is equivalent to
Java code Collection code
main{ 
   Connection con = null; 
   try{ 
      con = getConnection(); 
      methodA(); 
      con.commit(); 

cathc(RuntimeException ex){ 
con.rollback(); 

finally{ 
  closeCon(); 
}  
}  When MethodA is called

, there is no transaction in the environment, so a new transaction is opened.
When MethodB is called in MethodA , there is already a transaction in the environment, so methodB joins the current transaction.

PROPAGATION_SUPPORTS If a transaction exists, the current transaction is supported. If there is no transaction, non-transactional execution. But for transaction-synchronized transaction managers, PROPAGATION_SUPPORTS is slightly different from not using transactions.

Java code Collection code
//Transaction property PROPAGATION_REQUIRED  
methodA(){ 
  methodB(); 

 
//Transaction property PROPAGATION_SUPPORTS  
methodB(){ 
  ... 


When methodB is simply called, the methodB method is executed non-transactionally.
When methodA is called, methodB is added to the transaction of methodA and executed transactionally.

PROPAGATION_MANDATORY If a transaction already exists, the current transaction is supported. Throws an exception if there is no active transaction.

Java code Collection code
//Transaction property PROPAGATION_REQUIRED  
methodA(){ 
  methodB(); 

 
//Transaction property PROPAGATION_MANDATORY  
methodB(){ 
  ... 


When methodB is called alone, because there is currently no active transaction, an exception
throw will be thrown new IllegalTransactionStateException("Transaction propagation 'mandatory' but no existing transaction found");

When methodA is called, methodB is added to the transaction of methodA and executed transactionally.

PROPAGATION_REQUIRES_NEW always starts a new transaction. If a transaction already exists, suspend the existing transaction.

Java code Collection code
//Transaction property PROPAGATION_REQUIRED  
methodA(){ 
  doSomeThingA(); 
methodB(); 
doSomeThingB(); 

 
//Transaction property PROPAGATION_REQUIRES_NEW  
methodB(){ 
  ... 


When calling methodB alone, it is equivalent to declaring methodb as REQUIRED. Start a new transaction and execute it transactionally.

When calling methodA, the
Java code collection code
main(){ 
  methodA(); 

is quite different. It is equivalent to the following effect.
Java code Collection code
main(){ 
TransactionManager tm = null; 
try{ 
  //Get a JTA transaction manager 
   tm = getTransactionManager(); 
   tm.begin();//Open a new transaction 
   Transaction ts1 = tm.getTransaction() ; 
   doSomeThing(); 
   tm.suspend();//Suspend the current transaction 
   try{ 
     tm.begin();//Restart the second transaction 
     Transaction ts2 = tm.getTransaction(); 
     methodB(); 
     ts2.commit();//Commit the second transaction 
      
   } 
  Catch(RunTimeException ex){ 
     ts2.rollback();//Rollback the second transaction 
  } 
  finally{ 
    //Release resources 
  } 
   //After methodB is executed, return Resume the first transaction 
   tm.resume(ts1); 
doSomeThingB(); 
   ts1.commit();//Commit the first transaction 

catch(RunTimeException ex){ 
  ts1.rollback();//Rollback the first transaction 

finally{ 
  //Release resources 



Here, I call ts1 the outer transaction and ts2 the inner transaction. As can be seen from the above code, ts2 and ts1 are two independent transactions that are not related to each other. The success of Ts2 does not depend on ts1. If the methodA method fails the doSomeThingB method after calling the methodB method, the result of the methodB method is still submitted. The results caused by other code except methodB are rolled back.
To use PROPAGATION_REQUIRES_NEW, you need to use JtaTransactionManager as the transaction manager.

PROPAGATION_NOT_SUPPORTED always executes non-transactionally and suspends any existing transactions.

Java code Collection code
//Transaction property PROPAGATION_REQUIRED  
methodA(){ 
  doSomeThingA(); 
methodB(); 
doSomeThingB(); 

 
//Transaction property PROPAGATION_NOT_SUPPORTED  
methodB(){ 
  ... 


When methodB is called alone, no transaction mechanism is enabled, Execute non-transactionally.
When calling methodA, it is equivalent to the following effect

Java code Collection code
main(){ 
TransactionManager tm = null; 
try{ 
  //Get a JTA transaction manager 
   tm = getTransactionManager(); 
   tm.begin();//Open a new one Transaction 
   Transaction ts1 = tm.getTransaction(); 
   doSomeThing(); 
   tm.suspend();//Suspend the current transaction 
     methodB(); 
   //After methodB is executed, restore the first transaction 
   tm.resume(ts1); 
doSomeThingB(); 
   ts1.commit();//Commit the first transaction 

catch(RunTimeException ex){ 
  ts1.rollback(); //Rollback the first transaction 

finally{ 
  //Release resources 


Use PROPAGATION_NOT_SUPPORTED, and also need to use JtaTransactionManager as a transaction manager.

PROPAGATION_NEVER is always executed non-transactionally, if there is an active transaction, an exception is thrown

Java code Collection code
//Transaction property PROPAGATION_REQUIRED  
methodA(){ 
  doSomeThingA(); 
methodB(); 
doSomeThingB(); 

 
//Transaction property PROPAGATION_NEVER  
methodB( ){ 
  ... 

calls methodB alone, which is non-transactional execution.
Calling methodA will throw an exception
throw new IllegalTransactionStateException(
"Transaction propagation 'never' but existing transaction found");


PROPAGATION_NESTED If an active transaction exists, run in a nested transaction. If there is no active transaction, execute by the TransactionDefinition.PROPAGATION_REQUIRED property

This is a Nested transactions, when using the JDBC 3.0 driver, only supports DataSourceTransactionManager as a transaction manager. Requires the java.sql.Savepoint class for the JDBC driver. There are some JTA transaction manager implementations that may provide the same functionality.

To use PROPAGATION_NESTED, you also need to set the nestedTransactionAllowed property of PlatformTransactionManager to true;
and the default value of the nestedTransactionAllowed property is false;
Java code Collection code
//Transaction property PROPAGATION_REQUIRED  
methodA(){ 
  doSomeThingA(); 
methodB(); 
doSomeThingB(); 

 
// Transaction property PROPAGATION_NESTED 
methodB(){ 
  ... 


If the methodB method is called alone, it is executed according to the REQUIRED attribute.

If the methodA method is called, it is equivalent to the following
Java code Collection code
main(){ 
Connection con = null; 
Savepoint savepoint = null; 
try{ 
  con = getConnection(); 
  con.setAutoCommit(false); 
  doSomeThingA(); 
  savepoint = con2 .setSavepoint(); 
  try 
      methodB(); 
  }catch(RuntimeException ex){ 
     con.rollback(savepoint); 
  } 
  finally{ 
    //Release resources 
  } 
 
  doSomeThingB(); 
  con.commit(); 

catch(RuntimeException ex){ 
  con .rollback(); 

finally{ 
  //Release resources 


When the methodB method is called, call the setSavepoint method to save the current state to savepoint. If the methodB method call fails, restore the previously saved state. However, it should be noted that the transaction is not committed at this time. If the subsequent code (doSomeThingB() method) fails to be called, all operations including the methodB method will be rolled back.

A very important concept of nested transactions is that the inner transaction depends on the outer transaction. When the outer transaction fails, the actions done by the inner transaction are rolled back. The failure of the inner transaction operation will not cause the rollback of the outer transaction.

The difference between PROPAGATION_NESTED and PROPAGATION_REQUIRES_NEW: They are very similar, they are like a nested transaction, if there is no active transaction, a new transaction will be opened. When using PROPAGATION_REQUIRES_NEW, the inner transaction and the outer transaction are like two independent transactions. Once the inner transaction is committed, the outer transaction cannot be rolled back. The two transactions do not affect each other. Two transactions are not a true nested transaction. At the same time it requires the support of the JTA transaction manager.
When PROPAGATION_NESTED is used, the rollback of the outer transaction can cause the rollback of the inner transaction. The exception of the inner transaction will not cause the rollback of the outer transaction, it is a real nested transaction. When DataSourceTransactionManager uses savepoint to support PROPAGATION_NESTED, JDBC driver 3.0 or higher and JDK version 1.4 or higher are required. Other JTA TrasactionManager implementations may have different support.

PROPAGATION_REQUIRED should be our first transaction propagation behavior. It meets most of our business needs.

Guess you like

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