Previously summary
When writing a business-layer approach, there are many operations that require transactional submissions, and the spring framework provides a handy way to add @transactional annotations to the methods that require transactional submissions, much simpler than opening transactions, committing and controlling rollbacks ourselves. But it's easy to make some mistakes when you use them. I would like to summarize my own mistakes as follows.
Dull background knowledge (can be ignored)
Programmatic transaction Management & Declarative Transaction management:
(i) Programmatic transaction management before Spring appears, programmatic transaction management is the only option for POJO-based applications. People with Hibernate know that we need to explicitly invoke BeginTransaction (), commit (), rollback () and other transaction management related methods in code, which is programmatic transaction management. With the transaction management API provided by Spring, we can flexibly control the execution of transactions in code. At the bottom, Spring still delegates transactional operations to the underlying persistence framework for execution.
(ii) declarative transaction management
1) Spring's declarative transaction management is based on AOP at the bottom. The essence is to intercept the method before and after it, and then create or join a transaction before the target method starts, committing or rolling back the transaction according to execution after the target method is executed.
2) The greatest advantage of declarative transactions is that you do not need to programmatically manage transactions, so that you do not need to mix transaction-managed code in your business logic code, and you can apply transaction rules to your business logic by simply making the relevant transaction rule declarations in the configuration file (or through an equivalent label-based approach). Because transaction management is a typical crosscutting logic in itself, it is where AOP comes in. The Spring development team is aware of this and provides simple and powerful support for declarative transactions.
3) declarative transaction management has been a highlight of EJB's pride, and spring has enabled POJO to have the same benefits as EJB in transaction management, allowing developers to use a powerful declarative transaction management feature outside of the EJB container, mainly thanks to the Spring-dependent injection container and SPR ing AOP support. The Dependency injection container provides the infrastructure for declarative transaction management, which makes the Bean manageable for the spring framework, while Spring AOP is the direct implementation of declarative transaction management.
4) It is recommended to use declarative transactions in development, not only because of its simplicity, but also because it makes pure business code non-polluting and greatly facilitates later code maintenance. The only disadvantage of declarative transactions, compared to programmatic transactions, is that the finer granularity of the latter only works at the method level and cannot be scoped to the code block as a programmatic transaction. But even with this requirement, there are many workarounds, such as the ability to separate code blocks that require transaction management into methods, and so on.
As you can see from the @transactional code, the configurable parameters are:
- Transaction ISOLATION Level:
Isolation isolation() default Isolation.DEFAULT;
- Transactional propagation Behavior:
Propagation propagation() default Propagation.REQUIRED;
- The exception class that rolls back and does not roll back:
rollbackFor() noRollbackFor()
- Timeout:
int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
MySQL's Innob engine supports four levels of standard SQL transactions:
Repeatable READ (default)
| READ COMMITTED
| READ UNCOMMITTED
| SERIALIZABLE
The default is repeatable read, take Repeatable_read as an example, by default it uses consistent nonlocking Reads, in fact, is a multi-version snapshot mode, a repeatable_read transaction inside, the first read from the database fetch, Then this data into the snapshot, the back of the read is taken from the snapshot, so that although the consistency of the data read in a transaction, but there will be other transactions have changed the value of the database, and the current transaction is still using the old data. If the synchronization requirements for data are high, you can use locks on SQL
Select ... lock in share mode; Shared lock, can be read at the same time, cannot write simultaneously
Select ... for update; Exclusive lock, Exclusive
But with locks, it certainly affects performance, at least MySQL does not use locks to implement the Repeatable-read isolation level.
In the case of the serializable level, MySQL will automatically convert the Select to select ... Lock in SHARE MODE, which uses a shared lock.
Transactional propagation behavior: the so-called transactional behavior is that if a transaction context already exists before the current transaction is started, there are several options to specify the execution behavior of a transactional method. The transactiondefinition definition includes the following constants that represent propagation behavior:
1. Transactiondefinition.propagation_required: If a transaction is currently present, join the transaction, or create a new transaction if there is no current transaction.
2. Transactiondefinition.propagation_requires_new: Creates a new transaction and suspends the current transaction if a transaction is currently present.
3. Transactiondefinition.propagation_supports: If a transaction is currently present, the transaction is joined, and if no transaction is currently present, it will continue to run in a non-transactional manner.
4. Transactiondefinition.propagation_not_supported: Runs in a non-transactional manner and suspends the current transaction if a transaction is currently present.
5. Transactiondefinition.propagation_never: Runs in a non-transactional manner and throws an exception if a transaction is currently present.
6. Transactiondefinition.propagation_mandatory: If a transaction is currently present, the transaction is joined and an exception is thrown if there is no current transaction.
7. Transactiondefinition.propagation_nested: If a transaction is currently present, create a transaction to run as a nested transaction for the current transaction, or if there is no current transaction, The value is equivalent to transactiondefinition.propagation_required.
It should be noted here that the previous six transactional propagation behaviors were introduced by Spring from the EJB and shared the same concepts. And propagation_nested is unique to Spring. A propagation_nested-initiated transaction is embedded in an external transaction (if there is an external transaction), at which point the inline transaction is not a separate transaction, it relies on the existence of the external transaction, and only commits the external transaction to cause the internal transaction to be committed. Nested child transactions cannot be submitted separately. If you are familiar with the concept of savepoint (savepoint) in JDBC, then nested transactions are easy to understand, in fact, nested sub-transactions is an application of the savepoint, a transaction can include multiple savepoint, each nested child transaction. Also, a rollback of an external transaction results in a rollback of the nested transaction.
Summarize:
- Transactional annotations can be applied to interface definitions and interface methods, class definitions, and public methods of classes.
- The "Proxy-target-class" property value to control whether an interface-based or class-based proxy is created. <tx:annotation-driven transaction-manager= "TransactionManager" proxy-target-class= "true"/> Note: The Proxy-target-class property value determines whether an interface-based or class-based proxy is created. If the Proxy-target-class property value is set to True, then the class-based proxy will function (this requires the Cglib library). If the Proxy-target-class value is set to False or if this attribute is omitted, then the standard JDK is based on the agent of the interface.
- Note @transactional Cglib and Java dynamic Agent The biggest difference is that the proxy target object is not implemented interface, then if the annotation is written to the interface method, if the use of Cglib proxy, this is the annotation of the thing is invalid, in order to maintain the compatibility annotations are best written to the implementation class method.
- The spring team recommends using @Transactional annotations on specific classes (or methods of classes) instead of using any interfaces that the class implements. Using @Transactional annotations on an interface only takes effect if you set up an interface-based proxy. Because annotations are not inherited, this means that if a class-based proxy is being used, the transaction's settings will not be recognized by the class-based proxy, and the object will not be wrapped by the transaction proxy.
- @Transactional transactions are opened, either interface-based or class-based proxies are created. So in the same class one method calls another method with a transactional method, and the transaction does not work. Reason: (which is why some @async in the project are not executed asynchronously) spring scans the bean to see if the method contains @transactional annotations, and if it does, spring dynamically generates a subclass (that is, the proxy class) for the Bean. Proxy), the surrogate class is inherited from the original bean. At this point, when the annotated method is called, it is actually called by the proxy class, and the proxy class starts transaction before the call. However, if this annotated method is called by other methods in the same class, then the call to the method does not pass through the proxy class, but directly through the original bean, so it does not start transaction, and the phenomenon we see is that the @transactional annotation is invalid.
Tips: When using ~for update to implement pessimistic locking, you need to pay attention to the level of lock, Mysql InnoDB default row-level lock . Row-level locks are indexed, and if an SQL statement is not indexed, row-level locks are not used, and the table level is used to lock the entire table, which needs attention.
Tips: When using optimistic locking, most implementations use a version number, or a timestamp. However, if the isolation level of a transaction allows repetition (for example: Repeatable_read;mysql InnoDB is the default), then using optimistic locking is a variation of the query version or timestamp, but Oracle can do so by default.
Tips: Spring The default transaction isolation level is the isolation level of the underlying data area. So, if you're using MySQL's InnoDB engine, then the level is: repeatable read; If you're using Oracle, then the level is read commited.
Tips: Spring's @transactional annotation transaction creation behavior The default value is: propagation_required
The above is I can think of the relevant, if there are mistakes I hope everyone in time and I discuss.
Related Enquiry Information:
[http://zliguo.iteye.com/blog/2230013]
[http://my.oschina.net/guanzhenxing/blog/214228]
[HTTP://BLOG.CSDN.NET/U012228718/ARTICLE/DETAILS/42750119#T1]
[http://my.oschina.net/yybear/blog/103235]
[http://my.oschina.net/feichexia/blog/202520]
[http://www.hollischuang.com/archives/934]
[http://blog.csdn.net/clementad/article/details/47339519]
(Original address: http://mojito515.github.io/blog/2016/08/31/transactionalinspring/)
When you use @transactional annotations in spring, you may want to be aware of where