Detailed explanation of spring transactions

Spring transaction properties are transferred from: http://blog.csdn.net/aaaaaaaa0705/article/details/6726108
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.
Code



Java Code Collection Code
01. <span style="font-size: small;"><span style="font-size: x-small;">TransactionDefinition 
02. public interface TransactionDefinition { 
03. int getPropagationBehavior(); 
04 .int getIsolationLevel();  05.int getTimeout();
06.boolean 
isReadOnly(); 
07. }</span> 
08.  
09.  
10.  
11. </span> 




The 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 is 1000, the financial staff changed Mary's salary to 8000, but did not submit the transaction
Code



Java Code Collection Code
01. <span style="font-size: x-small;">Connection con1 = getConnection( ); 
02. con.setAutoCommit(false); 
03. update employee set salary = 8000 where empId = "Mary"; </span> 




At the same time, Mary is reading her own salary
Code




Java Code Favorite Code
01. Connection con2 = getConnection(); 
02. select salary from employee where empId = "Mary"; 
03. con2.commit();  
 

Mary finds that her salary has changed to 8000, happy!
The finance found that the operation was wrong, and the transaction was rolled back, and Mary's salary became 1000
code




Java code Collection code
01. //con1 
02. con1.rollback();  
 

Like this, the salary number 8000 recorded by Mary is a dirty data.
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 reads her own salary as 1000, and the operation is not completed.
Code




Java code Collection code
01. con1 = getConnection(); 
02. select salary from employee empId = "Mary";  
 

In transaction 2, the financial staff modified Mary's salary to 2000 and submitted the transaction.
Code




Java code collection Code
01. con2 = getConnection(); 
02. update employee set salary = 2000; 
03. con2.commit();  
 

In transaction 1, when Mary reads her own salary again, the salary becomes 2000
Code




Java Code Collection Code
01 . //con1 
02. 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.
Code




Java Code Favorite Code
01. con1 = getConnection(); 
02. 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
code




Java code Collection code
01. con2 = getConnection(); 
02. Insert into employee(empId,salary) values("Lili",1000); 
03. con2.commit();  
 

Transaction 1 reads all employees whose salary is 1000 again
Code
1. //con1
2. 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.
Code




Java Code Favorite Code
01. //Transaction property PROPAGATION_REQUIRED 
02. methodA{ 
03. …… 
04. methodB(); 
05. …… 
06. } 
07. //Transaction property PROPAGATION_REQUIRED 
08. methodB{ 
09. 
  10. }  
 

Use spring declarative Transactions, Spring uses AOP to support declarative transactions. It will automatically decide whether to open a transaction before the method is called according to the transaction attributes, and decide whether to commit or roll back the transaction after the method is executed.
Call methodB method alone
Code
1. main{
2. metodB();
3. }
is equivalent to
code




Java code Collection code
01. Main{ 
02. Connection con=null; 
03. try{ 
04. con = getConnection(); 
05. con.setAutoCommit(false); 
06. //Method call 
07. methodB(); 
08. //Commit transaction 
09. con.commit(); 
10. } 
11. Catch(RuntimeException ex){ 
12. //Rollback the transaction 
13. con.rollback(); 
14. } 
15. finally{ 
16. //Release resources 
17. closeCon(); 
18. } 
19. }  
 

Spring guarantees that all invocations 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
Code




Java code Collection code
01. main{ 
02. Connection con = null; 
03. try{ 
04. con = getConnection(); 
05. methodA() ; 
06. con.commit(); 
07. } 
08. cathc(RuntimeException ex){ 
09. con.rollback(); 
10. } 
11. finally{ 
12. closeCon(); 
13. } 
14. }   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 join 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.
Code d




Java code Collection code
01. //Transaction property PROPAGATION_REQUIRED 
02. methodA(){ 
03. methodB(); 
04. } 
05.  
06. //Transaction property PROPAGATION_SUPPORTS 
07. methodB(){ 
08. 
  09. }  
 

When simply calling methodB, 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.
Code




Java Code Favorite Code
01. //Transaction property PROPAGATION_REQUIRED 
02. methodA(){ 
03. methodB(); 
04. } 
05.  
06. //Transaction property PROPAGATION_MANDATORY 
07. methodB(){ 
08. ... 
09. }  
 

When methodB is called alone, Because there is currently no active transaction, an exception
throw new IllegalTransactionStateException("Transaction propagation 'mandatory' but no existing transaction found") is thrown;
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.
Code




Java code Collection code
01. //Transaction property PROPAGATION_REQUIRED 
02. methodA(){ 
03. doSomeThingA(); 
04. methodB(); 
05. doSomeThingB(); 
06. } 
07. //Transaction property PROPAGATION_REQUIRES_NEW 
08. methodB(){ 
09. ...... 
10. }  
 

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




Java code Collection code
01. main(){ 
02. methodA(); 
03. }  
 

The situation is quite different. It is equivalent to the following effect.
Code




Java code Collection code
01. main(){ 
02. TransactionManager tm = null; 
03. try{ 
04. //Get a JTA transaction manager 
05. tm = getTransactionManager(); 
06. tm.begin();// Start a new transaction 
07. Transaction ts1 = tm.getTransaction(); 
08. doSomeThing(); 
09. tm.suspend();//Suspend the current transaction 
10. try{ 
11. tm.begin();// restart the second transaction 
12. Transaction ts2 = tm.getTransaction(); 
13. methodB(); 
14. ts2.commit();//Commit the second transaction 
15.  
16. } 
17. Catch(RunTimeException ex){ 
18. ts2.rollback ();//Rollback the second transaction 
19. } 
20. finally{ 
21. //Release resources 
22. } 
23. //After methodB is executed, restore the first transaction 
24. tm.resume(ts1) ; 
25. doSomeThingB(); 
26. ts1.commit();//Commit the first transaction 
27. } 
28. catch(RunTimeException ex){ 
29. ts1.rollback();//Roll back the first transaction 
30 . } 
31. finally{ 
32. //Release resources 
33. } 
34. }  
 

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.
Code
 



Java code Collection code
01. //Transaction property PROPAGATION_REQUIRED 
02. methodA(){ 
03. doSomeThingA(); 
04. methodB(); 
05. doSomeThingB(); 
06. } 
07.  
08. //Transaction property PROPAGATION_NOT_SUPPORTED 
09. methodB(){ 
10. ... 
11. } 
 
When methodB is called alone, no transaction mechanism is enabled, and it is executed non-transactionally.
When methodA is called, it is equivalent to the following effect
Code




Java Code Collection Code
01. main(){ 
02. TransactionManager tm = null; 
03. try{ 
04. //Get a JTA transaction manager 
05. tm = getTransactionManager(); 
06. tm.begin();//Start a new transaction 
07. Transaction ts1 = tm .getTransaction(); 
08. doSomeThing(); 
09. tm.suspend();//Suspend the current transaction 
10. methodB(); 
11. //After methodB is executed, resume the first transaction 
12. tm. resume(ts1); 
13. doSomeThingB(); 
14. ts1.commit();//Commit the first transaction 
15. } 
16. catch(RunTimeException ex){ 
17. ts1.rollback();//Roll back the first transaction A transaction 
18. } 
19. finally{ 
20. //Release resources 
21. } 
22. }  
 

With PROPAGATION_NOT_SUPPORTED, you also need to use JtaTransactionManager as the transaction manager.
PROPAGATION_NEVER always executes non-transactionally, throws an exception if there is an active transaction
Code




Java Code Collection Code
01. //Transaction property PROPAGATION_REQUIRED 
02. methodA(){ 
03. doSomeThingA(); 
04. methodB(); 
05. doSomeThingB (); 
06. } 
07.  
08. //Transaction property PROPAGATION_NEVER 
09. methodB(){ 
10. ... 
11. }  
 

If methodB is called alone, it is not a 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, press TransactionDefinition .PROPAGATION_REQUIRED property enforces
This is a nested transaction, when using the JDBC 3.0 driver, only DataSourceTransactionManager is supported 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;
code




Java code Collection code
01. //Transaction property PROPAGATION_REQUIRED 
02. methodA(){ 
03. doSomeThingA(); 
04. methodB( ); 
05. doSomeThingB(); 
06. } 
07.  
08. //Transaction property PROPAGATION_NESTED 
09. methodB(){ 
10. ... 
11. }  
 

If the methodB method is called separately, it will be executed according to the REQUIRED property.
If the methodA method is called, it is equivalent to the following effect
Code




Java code Collection code
01. main(){ 
02. Connection con = null; 
03. Savepoint savepoint = null; 
04. try{ 
05.     con = getConnection(); 
06.     con.setAutoCommit(false); 
07.     doSomeThingA(); 
08.     savepoint = con2.setSavepoint(); 
09.     try{ 
10.         methodB(); 
11.     }catch(RuntimeException ex){ 
12.         con.rollback(savepoint); 
13.     } 
14.     finally{ 
15.         //释放资源 
16.     } 
17.  
18.     doSomeThingB(); 
19.     con.commit(); 
20.    } 
21.     catch(RuntimeException ex){ 
22.     con.rollback(); 
23.    } 
24.    finally{ 
25.        //释放资源 
26.    } 
27. }  
 

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 This is 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=326772424&siteId=291194637