The spring transaction mechanism mainly includes declarative transactions and programmatic transactions, where declarative transactions are emphasized, and programmatic transactions are not widely used in real-world development, and are for reference only.
Spring declarative transactions let us get away from complex transaction processing. So that we no longer have to deal with these operations such as getting connections, closing connections, committing transactions, and rolling back. There is no need for us to deal with a lot of try...catch...finally code in transaction-related methods. A very important concept when we use Spring declarative transactions is transaction properties. Transaction properties are typically composed of the propagation behavior of the transaction, the isolation level of the transaction, the timeout value of the transaction, and the transaction read-only flag. When we are doing a transaction partition, we need to define the transaction, that is, to configure the properties of the transaction.
The following is a detailed explanation of the four properties of the transaction, only for your study reference:
Spring defines these properties in the Transactiondefinition interface for Platfromtransactionmanager use. Platfromtransactionmanager is the core interface of spring transaction management.
Public interface Transactiondefinition {
int Getpropagationbehavior ();//Returns the propagation behavior of a transaction.
int Getisolationlevel ();//Returns the isolation level of a transaction, which the transaction manager controls to see what data within the transaction can be seen by another transaction.
int gettimeout ();//The return transaction must be completed in the number of seconds.
Boolean isreadonly ();//Whether the transaction is read-only and the transaction manager is able to optimize based on this return value to ensure that the transaction is read-only.
}
1. Define five isolation levels in the Transactiondefinition interface:
Isolation_default This is a platfromtransactionmanager default isolation level, using the database default transaction isolation level. The other four correspond to the isolation level of JDBC;
Isolation_read_uncommitted This is the lowest isolation level for transactions, and it allows a transaction to see uncommitted data for this transaction. This isolation level produces dirty reads, non-repeatable reads, and Phantom reads.
Isolation_read_committed guarantees that a transaction modified data is committed before it can be read by another transaction. Another transaction cannot read uncommitted data for the transaction. This level of transaction isolation avoids dirty reads, but non-repeatable reads and phantom reads can occur.
Isolation_repeatable_read This transaction isolation level prevents dirty reads and cannot be read repeatedly. However, Phantom reads may occur. In addition to ensuring that one transaction cannot read uncommitted data from another transaction, it ensures that the following conditions are avoided (non-repeatable read).
Isolation_serializable This is the most cost-effective, but most reliable, transaction isolation level. Transactions are processed for sequential execution. In addition to preventing dirty reading, non-repeatable reading, but also avoids phantom reading.
1:dirty reads (dirty read). In other words, the uncommitted (and still cached) data for transaction A is read by transaction B, and if transaction a fails to roll back, the data read by transaction B is wrong.
2:non-repeatable reads (data cannot be read repeatedly). For example, the value of reading data-total-two places in transaction a. At the first reading, total is 100, then transaction b changes the total data to 200, and transaction a reads again, and the result is that total turns out to be 200, causing transaction a data chaos.
3:phantom reads (phantom read data), which is similar to non-repeatable reads, is also an issue that is inconsistent with multiple reads in the same transaction. But non-repeatable reads is inconsistent because the data set he wants to take is changed (such as total data), but the inconsistency of the data that Phantom reads to read is not a change in the data set that he wants to read, but a change in his conditional data set. For example, select Account.id where account.name= "ppgogo*", the first time to read 6 eligible IDs, the second time, because transaction B to the name of an account from "DD" to Change to "Ppgogo1", As a result, 7 data were taken out.
2. Seven transactional propagation behaviors are defined in the Transactiondefinition interface:
(1) propagation_required If there is a transaction, the current transaction is supported. If there is no transaction, a new transaction is opened.
Java code:
Transaction Property propagation_required
methoda{
......
MethodB ();
......
}
Transaction Property propagation_required
methodb{
......
}
With spring declarative transactions, Spring uses AOP to support declarative transactions, automatically deciding whether to open a transaction before a method call, based on the transaction properties, and then deciding the transaction to commit or roll back after the method executes.
Call the MethodB method separately:
Java code
main{
Metodb ();
}
Equivalent
Java code
main{
Connection con=null;
try{
con = getconnection ();
Con.setautocommit (false);
Method invocation
MethodB ();
Commit a transaction
Con.commit ();
}
Catch (RuntimeException ex) {
Rolling back a transaction
Con.rollback ();
}
finally{
Freeing resources
Closecon ();
}
}
Spring guarantees that all calls in the MethodB method get to the same connection. When calling MethodB, there is a transaction that does not exist, so a new connection is obtained and a new transaction is opened.
When MethodA is called separately, MethodB is called within MethodA.
The execution effect is equivalent to:
Java code
main{
Connection con = null;
try{
con = getconnection ();
MethodA ();
Con.commit ();
}
catch (RuntimeException ex) {
Con.rollback ();
}
finally{
Closecon ();
}
}
When calling MethodA, 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.
(2) Propagation_supports If there is a transaction, the current transaction is supported. If there is no transaction, the execution is non-transactional. However, for transaction managers with transactional synchronization, Propagation_supports is slightly different from not using transactions.
Java code:
Transaction Property propagation_required
MethodA () {
MethodB ();
}
Transaction Property Propagation_supports
MethodB () {
......
}
When invoking MethodB purely, the MethodB method is non-transactional execution. When Methda is called, MethodB is added to the MethodA transaction and executed in the transaction.
(3) Propagation_mandatory if a transaction already exists, the current transaction is supported. Throws an exception if there is no active transaction.
Java code:
Transaction Property propagation_required
MethodA () {
MethodB ();
}
Transaction Property Propagation_mandatory
MethodB () {
......
}
When MethodB is called separately because there is currently no active transaction, an exception throws the new Illegaltransactionstateexception ("Transaction propagation ' mandatory ' But no existing transaction found "); when MethodA is called, MethodB is added to the transaction of MethodA and executed by the transaction.
(4) Propagation_requires_new always opens a new transaction. If a transaction already exists, the existing transaction is suspended.
Java code:
Transaction Property propagation_required
MethodA () {
Dosomethinga ();
MethodB ();
DOSOMETHINGB ();
}
Transaction Property Propagation_requires_new
MethodB () {
......
}
Java code:
Main () {
MethodA ();
}
Equivalent
Java 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 current transaction
try{
Tm.begin ();//re-open a second transaction
Transaction ts2 = Tm.gettransaction ();
MethodB ();
Ts2.commit ();//Commit a second transaction
}
Catch (RuntimeException ex) {
Ts2.rollback ();//rollback of the second transaction
}
finally{
Freeing resources
}
MethodB after execution, restore the first business
Tm.resume (TS1);
DOSOMETHINGB ();
Ts1.commit ();//Submit First Transaction
}
catch (RuntimeException ex) {
Ts1.rollback ();//rollback of the first transaction
}
finally{
Freeing resources
}
}
Here, I call ts1 the outer transaction, TS2 called the inner transaction. As can be seen from the above code, TS2 and Ts1 are two separate transactions that are irrelevant to each other. The success of TS2 is not dependent on ts1. If the MethodA method fails with the DOSOMETHINGB method after calling the MethodB method, the result of the MethodB method is still committed. The results of the code other than MethodB are rolled back. With propagation_requires_new, you need to use Jtatransactionmanager as the transaction manager.
(5) propagation_not_supported is always executed in a non-transactional manner and suspends any existing transactions. With propagation_not_supported, you also need to use Jtatransactionmanager as the transaction manager. (code example above, can be introduced similarly)
(6) Propagation_never is always performed in a non-transactional manner and throws an exception if there is an active transaction;
(7) propagation_nested If an active transaction exists, it is run in a nested transaction. If there is no active transaction, it is performed by the Transactiondefinition.propagation_required property. This is a nested transaction that only supports Datasourcetransactionmanager as the transaction manager when using the JDBC 3.0 driver. A JDBC-driven Java.sql.Savepoint class is required. There are some JTA transaction manager implementations that may also provide the same functionality. With propagation_nested, you also need to set Platformtransactionmanager's Nestedtransactionallowed property to true; Nestedtransactionallowed property value defaults to false;
Java code:
Transaction Property propagation_required
MethodA () {
Dosomethinga ();
MethodB ();
DOSOMETHINGB ();
}
Transaction Property propagation_nested
MethodB () {
......
}
If the MethodB method is called separately, it is performed by the required property. If you call the MethodA method, it is equivalent to the following effect:
Java 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{
Freeing resources
}
DOSOMETHINGB ();
Con.commit ();
}
catch (RuntimeException ex) {
Con.rollback ();
}
finally{
Freeing resources
}
}
When the MethodB method is called, the Setsavepoint method is called, saving the current state to savepoint. If the MethodB method call fails, it reverts to the previously saved state. It is important to note, however, that the transaction is not committed at this time, and if the subsequent code (DOSOMETHINGB () method) call fails, the rollback includes all operations of the MethodB method.
Nested transactions A very important concept is that the inner transaction relies on the outer layer. When the outer transaction fails, the actions of the inner layer are rolled back. The failure of the inner transaction operation does not cause the rollback of the outer transaction.
The difference between propagation_nested and propagation_requires_new: They are very similar, like a nested transaction, and if there is no active transaction, a new transaction will be opened. With Propagation_requires_new, the inner transaction and the outer transaction are like two separate transactions, and once the inner transaction commits, the outer transaction cannot roll it back. Two transactions do not affect each other. Two transactions are not a true nested transaction. It also requires the support of the JTA transaction manager.
When using propagation_nested, the rollback of the outer transaction can cause a rollback of the inner transaction. The exception of the inner transaction does not cause the rollback of the outer transaction, which is a true nested transaction. Datasourcetransactionmanager with savepoint support for propagation_nested, JDBC 3.0 or more drivers and more than 1.4 JDK version support are required. Other JTA Trasactionmanager implementations may have different support options.
Propagation_requires_new starts a new, "internal" transaction that does not depend on the environment. This transaction will be fully commited or rolled back without relying on external transactions, it has its own isolation range, its own locks, and so on. When an internal transaction starts executing, the external transaction will be suspended and the external transaction will continue to execute at the end of the housekeeping transaction.
On the other hand, propagation_nested begins a "nested" transaction, which is a real child of a transaction that already exists. When the dive set starts executing, it will get a savepoint. If this nested transaction fails, we will roll back to this savepoint. A latent transaction is a part of an external transaction that is committed only after the external transaction has ended.
Thus, the biggest difference between propagation_requires_new and propagation_nested is that propagation_requires_new is entirely a new business, and propagation_nested is a child of an external transaction, and if an external transaction commits, a nested transaction is also commit, and the same rule applies to roll back.
Propagation_required should be our first transaction propagation behavior. It can satisfy most of our business needs.
A detailed explanation of Spring transaction mechanism