Transaction is to ensure the atomicity, consistency, isolation, and permanence of logical processing.
With transaction control, you can avoid a series of problems, such as dirty data, caused by the failure of logical processing.
Transactions have two important features:
- The propagation behavior of a transaction
- Data isolation Level
1. Transaction propagation behavior (Transaction Behavior)
The propagation behavior level, which defines the control scope of the transaction. The popular point is that when you execute to a piece of code, you have different ways of handling existing transactions.
Spring complements and expands the level of transaction isolation for JDBC, and proposes 7 transactional propagation behaviors.
1) 7 Kinds of propagation behavior provided in Spring
propagation_required, transaction processing is required. If one is used, none is new. This is the default transaction propagation behavior for Spring. The attribute of this level is that if a transaction already exists in the context, then the code that is currently required to use the transaction is added to the Context's transaction, and if no transaction exists in the current context, a new transaction execution code is created. This level usually satisfies most business scenarios.
Propagation_supports, supports transaction processing. The attribute of this level is that if there is a transaction in the context, the code is added to the context's transaction execution, and if there is no transaction in the context, it is performed in a non-transactional manner.
Propagation_mandatory, the mandatory requirements of the business. The attribute of this level is that when executing code in a transactional manner, a transaction must already exist in the Context, or an exception will be thrown! Using MANDATORY to enforce transactions, you can effectively control the occurrence of "code that must be executed in a transaction, but forget to add transaction control" to it. As a simple example: there is a way that the requirement for this method is that once called, the method must be included in the transaction in order to execute properly, then this method is appropriate to set the Propagation_mandatory to enforce the transaction propagation behavior, which is controlled at the code level.
Propagation_requires_new, create a new transaction each time. The characteristic of this level is that when executing a code that requires a transaction, it is first judged whether a transaction exists in the Context, if it does not exist, creates a new transaction, if it already exists, suspend suspends the current transaction, and then creates a new transaction to execute until the new transaction is completed. Before resuming a previously suspended Context transaction.
propagation_not_supported, transactions are not supported. This level is characterized by suspending the transaction if a transaction exists in the current context, then executing the logic code, and then resuming the previously suspended context transaction after execution is complete. This propagation behavior of the transaction, can narrow the scope of the transaction process. As a simple example, in a transaction, it is necessary to invoke a non-core business logic Operation 1000 times, if the logic is placed in a transaction, it will cause the scope of the transaction to become larger, longer life cycle, in order to avoid due to the expansion of the scope of the transaction, the period is longer and caused some of the unexpected anomalies occurred, This logic can be set to not_supported does not support transactional propagation behavior.
Propagation_never, the transaction requirements are more stringent, the transaction cannot occur! This level is characterized by the setting of the level of code, once the execution of the Context of a transaction exists, will throw Runtime exception, forced to stop execution, I have no him!
propagation_nested, nested transactions. This level is characterized by the addition of transaction B of the current code to internal transaction A, nested execution if there is a transaction a in the context, and a new transaction execution code if there is no transaction in the context. In other words, between transaction A and transaction B is a parent-child relationship, A is a father, and B is a child. The key to understanding nested transactions is: Save point.
Description of parent, child transaction nesting, save point:
- The parent transaction creates a save point before the child transaction enters;
- Child transaction Rollback, the parent transaction is only rolled back to save point, and the entire parent transaction is not rolled back;
- A child transaction must be commit before the parent transaction commits.
2) Code example description
I see an article on the Internet, in the form of code to explain the level of transaction propagation behavior, the code is very clear, one can see.
First, prepare the following two Service:
class ServiceA { voidmethodA() { ServiceB.methodB(); }}class ServiceB { voidmethodB() { }}
- if
serviceb.methodb ()
has a propagation behavior defined as propagation_required
, then execute servicea.methoda ()
, if Servicea.methoda ()
has opened the transaction, call Serviceb.methodb ()
, Serviceb.methodb ( The
will run inside the transaction in Servicea.methoda ()
and no longer open a new transaction. And if Servicea.methoda ()
finds itself not in a transaction, it assigns a new transaction to it. In this way, if an exception occurs in Servicea.methoda ()
or anywhere within serviceb.methodb ()
, the transaction will be rolled back. Even if the transaction for Serviceb.methodb ()
has been
committed, but Servicea.methoda ()
fail to rollback in the next procedure, Serviceb.methodb ()
will also be rolled back along with it.
- if
Servicea.methoda ()
has the propagation behavior set to propagation_required
, serviceb.methodb ()
is propagation_requires_new
, then Servicea.methoda () when executed to Serviceb.methodb ()
The transaction where the
is located hangs, and Serviceb.methodb ()
will start a new transaction, waiting for the transaction of Serviceb.methodb ()
to finish, and A's transaction will continue to execute. The transaction difference between propagation_required
and propagation_requires_new
is the degree of rollback of the transaction. Because Serviceb.methodb
is a new transaction, there are two different transactions. If Serviceb.methodb
has been committed, then Servicea.methoda
fails to roll back, and Serviceb.methodb
is not rolled back. If Serviceb.methodb
fails to roll back, if the exception it throws is captured by Servicea.methoda
, Servicea.methoda
The transaction may still be committed.
- If
ServiceA.methodA
the transaction propagation behavior is PROPAGATION_REQUIRED
, and ServiceB.methodB
The transaction propagation behavior is PROPAGATION_NOT_SUPPORTED
, then when the transaction is executed, the transactions are ServiceB.methodB
ServiceA.methodA
suspended, and ServiceB.methodB
then the transactions are resumed after the non-transactional state has finished running ServiceA.methodA
.
- If
ServiceA.methodA
the transaction propagation behavior is PROPAGATION_REQUIRED
, and ServiceB.methodB
The transaction level is PROPAGATION_NEVER
, then ServiceB.methodB
execution throws an exception.
2. Data isolation levels (Isolation level)
In the process of reading a database, if two transactions are executed concurrently, what effect will the multiple transactions have on the data?
This leads to the second feature of the transaction: the data isolation level.
Data isolation level, which defines the scope of the transaction's control over the database-side read and write.
The data isolation level is divided into 4 types:
- Serializable: Serialization. This is the most stringent isolation level, serial execution between multiple transactions, and resource consumption is significant.
- REPEATABLE READ: Repeatable reading. This level ensures that the data has been read by the transaction and the other transaction cannot modify the data, thus avoiding "dirty reads" and "non-repeatable reads". There is still a large performance loss.
- Read commited: This is the default data isolation level for most mainstream databases. At this level, only the data that has been committed is allowed to be read. For example, when a transaction modifies data but is not committed, another parallel transaction will read only the content before the data is modified, thus avoiding "dirty reads".
- Read uncommited: One transaction can read data that has been modified but not yet committed by another parallel transaction. will produce a "dirty read".
The 1th data is of the highest accuracy, but with the worst performance. The 4th kind of performance is high, but the accuracy of reading the data accordingly is low.
3. Dirty reading, phantom reading, non-repeatable reading
Dirty reads, Phantom reads, non-repeatable reads are concurrent transactions, and are read differently because of different levels of data isolation.
Dirty Read (Dirty Reads)
Dirty reads, that is, one transaction reads data that has not yet been committed by another transaction. If the dirty read read to the final submission is still good, but if the data is eventually rolled back, then this data for the transaction just read to it is a dirty data.
Non-repeatable read (non-repeatable Reads)
Non-repeatable read, different transactions read the same piece of data, read the content is different. That is, for a single piece of data, different transactions are read in the same repetitive operation, but different results are produced.
Phantom Reading (Phantom Reads)
Phantom Read, a transaction according to a certain query condition, the first read the amount of data and the second read the amount of data is not the same, like a hallucination, obviously just looked at the N data, and then check it becomes m (M <> N).
4, how to reduce the transaction?
Suppose there are 20 conditions to check for a logical operation, can you put the checked content out of the transaction in order to reduce the transaction?
Many systems start a transaction in the inside of the DAO, and then perform the operation, either at the end of the commit or rollback. This involves the problem of code design.
Smaller systems can be used in this way, but in some larger systems, logic is more complex system, it is bound to put too much business logic into the DAO, resulting in a decline in the reusability of DAO. So this is not a good practice.
To answer this question, can you put some business logic checks out of the transaction in order to shrink the transaction?
The answer is: for the core business check logic, can not be placed outside the transaction, and must be distributed under the concurrency control! Once a check is made outside of a transaction, it is bound to cause the data that transaction A has checked to be modified by transaction B, resulting in a futile transaction A and concurrency problems that directly lead to business control failure.
Therefore, in the distributed high concurrency environment, the locking mechanism should be used for checking the core business logic.
For example, transaction opening needs to read a piece of data to verify, and then the logical operation needs to modify this data, and finally commit.
Such a process, if the read and verify the code is placed outside the transaction, then the read data is very likely to have been modified by other transactions, the current transaction once committed, will again overwrite the data of other transactions, resulting in data anomalies.
Therefore, when entering the current transaction, this data must be locked, for example, using Oracle for update
is a distributed environment in a very effective control means.
Another good practice is to use programmatic transactions rather than declarative transactions, especially in larger-scale projects. The declaration configuration for a large number of transactions will be a torment in the case of very large code volumes.
Keeping DAO at its most basic for a table, then processing the business logic into the manager or service, and using programmatic transactions to more precisely control the scope of the transaction.
In particular, it is important to note that in cases where exceptions can be thrown in a transaction, it is prudent to catch the exception, not to catch Exception casually, otherwise it will cause the exception of the transaction to be eaten and not be rolled back properly.
5. Spring Configuration declarative Transactions
Spring Configures declarative transactions:
- Configure Sessionfactory
- Configure Transaction Manager
- The propagation characteristics of a transaction
- Which classes are declared and which methods need to use transactions
To write a business logic method:
- By default, the run-time exception is rolled back (including inheriting the RuntimeException subclass), and normal exceptions are not rolled back
- When writing a business logic method, it is best to throw the exception up and down in the presentation layer (view) processing
- Settings on transaction boundaries are usually set to the business layer and not to Dao.
(1) Use the XML configuration method:
<!--configuration Sessionfactory --<beanid="Sessionfactory"class="Org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <propertyname="Configlocation"> <value>Classpath:hibernate.cfg.xml</value> </property></bean><!--Configure Hibernate transaction manager --<beanid="TransactionManager"class="Org.springframework.orm.hibernate3.HibernateTransactionManager"> <propertyname="Sessionfactory"ref="Sessionfactory"/></bean><!--definition notification: Define the propagation behavior of a transaction--<tx:adviceid="Txadvice"transaction-manager="TransactionManager"> <tx:attributes> <tx:methodname="add*"propagation="REQUIRED"/> <tx:methodname="del*"propagation="REQUIRED"/> <tx:methodname="modify*"propagation="REQUIRED"/> <tx:methodname="*"propagation="REQUIRED"read-only="true"/> </tx:attributes></tx:advice><!--declare which classes which methods need to use transactions --<aop:config> <aop:pointcutid="TRANSACTIONPC"expression="Execution (* com.service.*.* (..))"/> <aop:advisoradvice-ref="Txadvice"pointcut-ref="TRANSACTIONPC"/></aop:config><!--general IOC injection --<beanid="Usermanager"class="Com.service.UserManagerImpl"> <propertyname="Logmanager"ref="Logmanager"/> <propertyname="Sessionfactory"ref="Sessionfactory"/></bean><beanid="Logmanager"class="Com.service.LogManagerImpl"> <propertyname="Sessionfactory"ref="Sessionfactory"/></bean>
For instructions in spring configuration read-only
:
read-only
Configured to True to tell spring that the corresponding transaction should be optimized for read-only transactions.
This is one of the most optimized tips. In some cases, some transaction strategies can have a significant optimization effect, such as Object/Relational
avoiding dirty checking
(attempting to "refresh") when using mapping tools such as Hibernate or TopLink.
(2) using the JPA annotation method
@Service Public classUserserviceimplImplementsIuserservice {@ResourceIuserdao Userdao;//Start REQUIRED method of default transaction propagation behavior @Transactional Public void Funnone()throwsException {Save(New userentity("AAA")); }//Start REQUIRED method of default transaction propagation behavior @Transactional(propagation = propagation.)REQUIRED) Public void Funrequire()throwsException {Save(New userentity("BBB")); }//Start the Nested nested transaction method @Transactional(propagation = propagation.)NESTED) Public void funnest()throwsException {Save(New userentity("CCC")); }methods of//requires_new transactions @Transactional(propagation = propagation.)requires_new) Public void funrequirenew()throwsException {Save(New userentity("DDD")); }}
Reference article:
(Spring transaction propagation and isolation level) [http://blog.csdn.net/edward0830ly/article/details/7569954]
Http://blog.sina.com.cn/s/blog_4b5bc0110100z7jr.html
Understanding Spring Transaction propagation behavior and data isolation levels