Spring's transaction propagation behavior and isolation level

For details, please refer to the blog: https://bbs.csdn.net/topics/391875990

There are two concepts to understand:
1. "spring's transaction propagation properties"
2. "spring's transaction isolation level"

for example, a normal spring tag would be written like this:
@Transactional(propagation = Propagation.REQUIRED, isolation =Isolation.SERIALIZABLE)

propagation : Transaction propagation attribute
isolation: Transaction isolation level

1: What should I do if method a starts transaction a and calls method b to enable transaction b? How to spread? From transaction A to transaction B, what about transactions A and B?
2: Can the data read this time read data that has been modified by another transaction but has not been submitted? Wait, wait, the concepts involved are: dirty reading, phantom reading, etc.

 

Spring's transaction propagation properties:

PROPAGATION_REQUIRED--Support the current transaction, if there is no current transaction, create a new transaction. This is the most common choice.

PROPAGATION_SUPPORTS--Support the current transaction, if there is no current transaction, it will be executed in a non-transactional manner.

PROPAGATION_MANDATORY--Supports the current transaction, if there is no current transaction, an exception is thrown.

PROPAGATION_REQUIRES_NEW--Create a new transaction, if there is a current transaction, suspend the current transaction.

PROPAGATION_NOT_SUPPORTED--Perform the operation in a non-transactional manner, suspending the current transaction if there is a current transaction.

PROPAGATION_NEVER--Execute in a non-transactional manner, throwing an exception if there is currently a transaction.

 

1: PROPAGATION_REQUIRED

joins the transaction currently being executed is not in another transaction, then a new transaction is started.
For example, the transaction level of ServiceB.methodB is defined as PROPAGATION_REQUIRED,
then when ServiceA.methodA is executed, ServiceA.methodA has already started After the transaction is completed, ServiceB.methodB is called at this time. ServiceB.methodB sees that it is already running inside the transaction of ServiceA.methodA, so it will not start a new transaction. And if ServiceA.methodA runs and finds that he is not in a transaction, he will assign himself a transaction.

This way, if an exception occurs in ServiceA.methodA or anywhere within ServiceB.methodB, the transaction will be rolled back. Even if the transaction of ServiceB.methodB has been committed, but ServiceA.methodA will fail to roll back next, ServiceB.methodB will also roll back

2: PROPAGATION_SUPPORTS

If it is currently in a transaction, it runs in the form of a transaction, if it is no longer a In a transaction, then run in a non-transactional form

3: PROPAGATION_MANDATORY

must be run in a transaction. That is, he can only be called by a parent transaction. Otherwise, he will throw exception

4: PROPAGATION_REQUIRES_NEW

This is a bit of a twist.
For example, we design the transaction level of ServiceA.methodA to be PROPAGATION_REQUIRED, and the transaction level of ServiceB.methodB to be PROPAGATION_REQUIRES_NEW.

Then when ServiceB.methodB is executed, the transaction where ServiceA.methodA is located will be suspended, ServiceB.methodB will start a new transaction, and it will continue to execute after the transaction of ServiceB.methodB is completed. The difference between him and PROPAGATION_REQUIRED
is the degree of rollback of the transaction. Because ServiceB.methodB is a new transaction, then there are two different transactions. If ServiceB.methodB has been submitted, then ServiceA.methodA fails and rolls back, but ServiceB.methodB will not roll back. If ServiceB.methodB fails and rolls back, if the exception he throws is caught by ServiceA.methodA, the ServiceA.methodA transaction may still commit.

5: PROPAGATION_NOT_SUPPORTED

Transactions are not currently supported. For example, the transaction level of ServiceA.methodA is PROPAGATION_REQUIRED, and the transaction level of ServiceB.methodB is PROPAGATION_NOT_SUPPORTED, then when ServiceB.methodB is executed, the transaction of ServiceA.methodA is suspended, and it finishes running in a non-transactional state, and then continues ServiceA .methodA's transaction.

6: PROPAGATION_NEVER
cannot run within a transaction. Assuming that the transaction level of ServiceA.methodA is PROPAGATION_REQUIRED,
and the transaction level of ServiceB.methodB is PROPAGATION_NEVER, then ServiceB.methodB will throw an exception.

7: PROPAGATION_NESTED
The key to understanding Nested is the savepoint. The difference between him and PROPAGATION_REQUIRES_NEW is that PROPAGATION_REQUIRES_NEW starts another transaction, which will be independent of his parent transaction, while Nested's transaction is dependent on his parent transaction, and his submission is to be submitted together with his parent transaction. That is, if the parent transaction rolls back last, he will also roll back. And the nice thing about Nested affairs is that he has a savepoint.

  **************************************** ServiceA {

  /**

  * Transaction property configuration for PROPAGATION_REQUIRED

  */

  void methodA() {

  try {

  //savepoint

  ServiceB.methodB(); //PROPAGATION_NESTED level

  } catch (SomeException) {

  // perform other business, such as ServiceC.methodC();

  }

  }

  }

  **** ****************************************

  That means ServiceB.methodB fails and rolls back, Then ServiceA.methodA will also be rolled back to the savepoint point. ServiceA.methodA can choose another branch, such as
ServiceC.methodC, to continue to execute to try to complete its own transaction.

But this transaction is not defined in the EJB standard.

 

Let’s talk about the isolation level of a transaction:


First, you need to know a few concepts, all about reading:

what is dirty data, dirty read, non-repeatable read, phantom read?


Dirty read: A transaction reads an uncommitted update from another transaction data.
(Refers to when a transaction is accessing data and modifying the data, and the modification has not been submitted to the database, at this time,
another transaction also accesses the data, and then uses the data. Because the data is not yet Submitted data, then the data
read by another transaction is dirty data, and operations based on dirty data may be incorrect.)


Non-repeatable read: In the same transaction, the result returned by reading the same data multiple times Different
(refers to reading the same data multiple times within a transaction. Before the transaction is over, another transaction also accesses the same data.
Then, between the two reads in the first transaction, due to For the modification of the second transaction, the data read twice by the first transaction may be different. In this way, the data read twice in one transaction is different, so it is called non-repeatable read. . Repeatable read means that the data read multiple times is the same, that is, changes that have been committed by other transactions cannot be read.)


Phantom read: A transaction reads the insert data that has been committed by another transaction (meaning when the transaction is not A phenomenon that occurs when executed independently, for example, the first transaction modifies the data in a table, and this modification involves
all data rows in the table. At the same time, the second transaction also modifies the data in this table, This modification is to insert a new row of data into the table. Then, the user who operates the first transaction will find out that there are no modified data rows in the table in the future, just like an illusion.)



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

2.ISOLATION_READ_UNCOMMITTED: The lowest isolation level, to find out the uncommitted data of other transactions. Dirty reads, non-repeatable reads and phantom reads will occur, and generally no one will use them.

3.ISOLATION_READ_COMMITTED: Find out the data that other transactions have committed. Non-repeatable reads and phantom reads occur.

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

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

 

Commonly used parameters in the @Transactional annotation
readOnly
This property is used to set whether the current transaction is a read-only transaction. When set to true, it means read-only, and false means read-write. The default value is false. For example: @Transactional(readOnly=true)

Question 1. Does Propagation.NOT_SUPPORTED mean that transactions are not enabled? Does
             readOnly=true mean that only reading is supported?
             If the answer to the above two questions is yes, then this configuration is not Is there a conflict? Propagation.NOT_SUPPORTED does not open the transaction,
             and readOnly=true allows the transaction to only support reading. If the transaction is not opened, how to set the transaction to be read-only?

Answer 1: There is no conflict. NOT_SUPPORTED means that the operation is performed in a non-transactional manner. If there is a current transaction, the current transaction is suspended. Since there is no transaction, there is no read-only transaction, and readOnly is automatically ignored.



Question 2. I have such experience (pro-test), the code of the service layer remains unchanged, and then through the navicat tool in the mysql database, the field export_count of a record is
set to 10 and the setting is successful. Then go back to the code, break point debugging, and find that the value of export_count has not changed to 10 or the old data.
If you restart tomcat and then perform breakpoint debugging, the value of export_count becomes 10 at this time. This is also one of the things I don't understand.

Answer 2: There are several situations. First of all, it depends on whether your database is set to automatically commit transactions. Second, it depends on whether the code you use to update data has committed transactions.
It also depends on what database you are using, what is the default isolation level, and what is the default transaction isolation level of the spring you are using now
. There is no transaction isolation level setting in the code you read. The default value of , this situation has nothing to do with the propagation level, it is the isolation level thing!
It is also possible that you are using something like the second level cache of hibernate. It is recommended not to use those things and use redis or memcached to cache yourself Hotspot data.


Question 3. A transaction does not read the updated data of another transaction. Is this a dirty read? Unrepeatable read? Fake reading?
Answer 3: It depends on the specific situation. If you check N times during the query, keep holding a breakpoint, and then another thread modifies the data, then you are called
"repeatable read". If it is not the first case, it is that the transaction is not really committed when you update, it depends on the situation.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325669549&siteId=291194637