Spring transaction propagation mechanism & isolation level

Spring transaction propagation mechanism & isolation level

 

1. Propagation (propagation properties of transactions)


Propagation : The key property determines which method the proxy should add transactional behavior to. The most important part of such a property is the propagation behavior.

The following options are available:
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. After the execution of the current new transaction is completed, the context transaction is resumed and executed.
PROPAGATION_NOT_SUPPORTED--Execute the operation in a non-transactional manner. If there is a current transaction, suspend the current transaction, execute the current logic, and restore the context transaction after the end.
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 start a new transaction
. 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 there 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 After the execution of the current new transaction is completed, the context transaction will resume and execute again.
This is rather convoluted. 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 hang, and ServiceB.methodB will start a new one Transaction, waits for ServiceB.methodB's transaction to complete before
he continues to execute. The difference between him and the PROPAGATION_REQUIRED transaction 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. Rollback if ServiceB.methodB fails,
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 he 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 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 {


/**
* The transaction property is configured as PROPAGATION_REQUIRED
*/
void methodA() {
try {
//savepoint
ServiceB.methodB(); //PROPAGATION_NESTED level
} catch (SomeException) {
// Execute other business, such as ServiceC.methodC();
}
}


}
********************************************
That is ServiceB.methodB If it fails to roll back, then ServiceA.methodA will also be rolled back to the savepoint point. ServiceA.methodA can choose another branch, such as
ServiceC.methodC, and continue to execute to try to complete its own transaction.
But this transaction is not defined in the EJB standard.


So what is a nested transaction? Many people don't understand it. I have read some blogs, but there are some misunderstandings.
Nesting is that the sub-transaction is executed in the parent transaction. The sub-transaction is a part of the parent transaction. Before entering the sub-transaction, the parent transaction establishes a rollback point called save point, and then executes the sub-transaction. The execution of this sub-transaction is also considered Part of the parent transaction, then the child transaction execution ends and the parent transaction continues to execute. The point is that save point. It becomes clear from a few questions:
1) What happens if the subtransaction is rolled back? 
The parent transaction will roll back to the save point established before entering the child transaction, and then try other transactions or other business logic. The previous operations of the parent transaction will not be affected, and will not be automatically rolled back.
2) What happens if the parent transaction is rolled back? 
The parent transaction is rolled back, and the child transaction will also be rolled back! Why, because the child transaction will not be committed before the parent transaction ends. We say that the child transaction is a part of the parent transaction, which is exactly the reason. Then:
3) What is the commit of the transaction? 
Does the parent transaction commit first, and then the child transaction, or does the child transaction commit first, and then the parent transaction? The answer is the second case, or that sentence, the sub-transaction is a part of the parent transaction and is submitted by the parent transaction uniformly.






Isolation level of Spring transactions
 1. 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.
 2. ISOLATION_READ_UNCOMMITTED: This is the lowest isolation level of transactions, which fully A transaction outside the license can see the uncommitted data of this transaction.
      This isolation level produces dirty reads, non-repeatable reads and phantom reads.
 3. ISOLATION_READ_COMMITTED: To ensure that the data modified by one transaction can only be read by another transaction after it is committed. Another transaction cannot read the uncommitted data of the transaction
 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.


Exceptions in concurrent database operations:
1. Lost update: Both transactions update a row of data at the same time, but the second transaction fails and exits midway, resulting in invalidation of both modifications to the data. This is because the system does not execute any locks Operations are therefore not isolated from concurrent transactions.
2. Dirty Reads: A transaction starts to read a row of data but another transaction has updated the data but failed to commit in time. This is quite dangerous and it is possible that all operations are rolled back.
3. Non-repeatable Reads: A transaction reads the same row of data twice but gets different results. For example, in the middle of two reads, another transaction has modified the row data and committed it.
4. Second lost updates problem (Second lost updates problem): Unable to read the special case, there are two concurrent transactions that read the same row of data at the same time, and then one of them modifies it and commits the other, which will cause The first write operation fails.
5. Phantom Reads: Also known as phantoms (phantoms). The transaction performs two queries during the operation, and the result of the second query contains the data that did not appear in the first query (the SQL statement of the two queries is not required to be the same here). This is because there is another query during the two queries. Caused by transaction inserting data.
      In order to avoid the above situations, four transaction isolation levels are defined in the standard SQL specification, and different isolation levels handle transactions differently.
1. Unauthorized read (Read Uncommitted): Also known as uncommitted read. Dirty reads are allowed but update loss is not allowed. If one transaction has already started to write data, another data is not allowed to write at the same time, but other transactions are allowed to read this row of data. This isolation level can be achieved through "exclusive write locks". The lowest level of transaction isolation, only guaranteed not to read physically corrupted data. In contrast to the READ COMMITTED isolation level, it allows reading of data that has been modified by other users but has not yet been committed.
2. Authorized read (Read Committed): Also known as committed read. Non-repeatable reads are allowed but dirty reads are not allowed. This can be achieved through "instantaneous shared read locks" and "exclusive write locks". Transactions that read data allow other transactions to continue to access the row of data, but uncommitted write transactions will prevent other transactions from accessing the row. SQL Server default level. Under this isolation level, the SELECT command will not return uncommitted data, nor can it return dirty data.
3. Repeatable Read: Non-repeatable and dirty reads are prohibited. But sometimes phantom data can occur, which can be achieved through "shared read locks" and "exclusive write locks", where a read data transaction will prohibit a write transaction (but a read transaction is allowed), and a write transaction will prohibit any other transaction. Under this isolation level, the data read with the SELECT command will not be changed throughout the execution of the command. This option will affect the performance of the system, it is best not to use this isolation level if it is not necessary.
4. Serial (Serializable): Also known as serializable read. Provides strict transaction isolation, which requires serialization of transactions, and transactions can only be executed one after the other, but not concurrently. If transaction serialization cannot be achieved only through "row-level locks", other mechanisms must be used to ensure that newly inserted data will not be accessed by the transaction that just executed the query operation. The highest level of transaction isolation, complete isolation between transactions. Any concurrent overlapping transactions are guaranteed to be serial if the transaction runs at the serializable read isolation level.


Isolation Level Update Lost Dirty Read Repeated Read Phantom Read 
Unauthorized Read N Y Y Y 
Authorized Read N N Y Y 
Repeatable Read N N N Y 
Serial N N N N


So the safest is Serializable, but it also comes with high performance overhead.
In addition, there are two commonly used attributes of transactions: readonly and timeout
. One is to set the transaction to read-only to improve performance.
The other is to set the timeout period of the transaction, which is generally used to prevent the occurrence of large transactions. Again, keep things as small as possible!


Finally, a question is introduced:
There are 20 conditions that need to be checked for a logical operation. Can the checkable content be placed outside the transaction in order to reduce the transaction? 


Many systems start the transaction within the DAO, then perform the operation, and finally commit or roll back. This involves the problem of code design. Smaller systems can use this method, but in some larger systems and systems with
more complex logic, too much business logic is bound to be embedded in DAO, resulting in a decrease in the reusability of DAO. So this is not a good practice.

To answer the question: Can some business logic checks be placed outside the transaction in order to shrink the transaction? The answer is: For the core business check logic, it cannot be placed outside the transaction, and it must be used as a concurrency control under distributed!
Once the check is performed outside the transaction, it will inevitably cause the data that has been checked by transaction A to be modified by transaction B, resulting in futile transaction A and concurrency problems, which directly lead to the failure of business control.
Therefore, in a distributed high-concurrency environment, a locking mechanism should be used for checking the core business logic.
For example, when a transaction is opened, a piece of data needs to be read for verification, and then the data needs to be modified in the logical operation, and finally submitted.
In such a process, if the code read and verified is placed outside the transaction, the read data is likely to have been modified by other transactions. Once the current transaction is committed, the data of other transactions will be overwritten again, resulting in data abnormal.
Therefore, when entering the current transaction, this data must be locked. Using for update is a good control method in a distributed environment.


A good practice is to use programmatic transactions rather than lifetimes, especially on larger projects. For the configuration of the transaction, in the case of a very large amount of code, it will be a torture, and the human flesh way can never avoid this problem.
Keep the DAO for the most basic operations on a table, and then put the processing of business logic into the manager and service, and use programmatic transactions to control the scope of the transaction more precisely.
In particular, for some situations where exceptions may be thrown inside the transaction, the capture should be careful, and the exception of the transaction cannot be eaten casually and cannot be rolled back normally.
 
 
Spring configures declarative transactions:
* Configure SessionFactory
* Configure transaction manager
* Transaction propagation characteristics
* Those classes and those methods use transactions to
 
write business logic methods
* Inherit HibernateDaoSupport class, use HibernateTemplate for persistence, HibernateTemplate is
   a lightweight encapsulation of hibernate Session
* By default, runtime exceptions will be rolled back (including inheriting the RuntimeException subclass), ordinary exceptions will not be rolled back
* When writing business logic methods, it is best to throw exceptions all the way up and handle them in the presentation layer (struts)
* Regarding the settings of transaction boundaries, usually set to the business layer, do not add to Dao
 
<!-- Configure SessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="configLocation">
     <value>classpath:hibernate.cfg.xml</value>
    </property>
</bean>


<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>


<!-- 事务的传播特性 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
     <tx:method name="add*" propagation="REQUIRED"/>
     <tx:method name="del*" propagation="REQUIRED"/>
     <tx:method name="modify*" propagation="REQUIRED"/>
     <tx:method name="*" propagation="REQUIRED" read-only="true"/>
    </tx:attributes>
</tx:advice>


<!-- 哪些类哪些方法使用事务 -->
<aop:config>
    <aop:pointcut expression="execution(* com.service.*.*(..))" id="transactionPC"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="transactionPC"/>
</aop:config>


<!-- 普通IOC注入 -->
<bean id="userManager" class="com.service.UserManagerImpl">
    <property name="logManager" ref="logManager"/>
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="logManager" class="com.service.LogManagerImpl">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>

Guess you like

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