The use of @Transactional in Spring is described in detail

  • 2020-06-03 06:39:22
  • OfStack

The use of @Transactional in Spring is described in detail

Introduction: In spring, @Transactional provides a shortcut for controlling transaction management. However, many people just use @Transactional simply without in-depth understanding. This paper will explain the usage of each configuration item in depth.

1. Definition of @Transactional

The @Transactional in Spring is based on the dynamic proxy mechanism, which provides a transparent transaction management mechanism, convenient and quick to solve the problems encountered in the development. In reality, the actual problems are often much more complex than we expected, which requires a deep understanding of @Transactional to deal with complex problems.

First let's look at the @Transactional code definition:


@Target({ElementType.METHOD, ElementType.TYPE}) 
@Retention(RetentionPolicy.RUNTIME) 
@Inherited 
@Documented 
public @interface Transactional { 
 
  /** 
   * A qualifier value for the specified transaction. 
   * <p>May be used to determine the target transaction manager, 
   * matching the qualifier value (or the bean name) of a specific 
   * {@link org.springframework.transaction.PlatformTransactionManager} 
   * bean definition. 
   */ 
  String value() default ""; 
 
  /** 
   * The transaction propagation type. 
   * Defaults to {@link Propagation#REQUIRED}. 
   * @see org.springframework.transaction.interceptor.TransactionAttribute#getPropagationBehavior() 
   */ 
  Propagation propagation() default Propagation.REQUIRED; 
 
  /** 
   * The transaction isolation level. 
   * Defaults to {@link Isolation#DEFAULT}. 
   * @see org.springframework.transaction.interceptor.TransactionAttribute#getIsolationLevel() 
   */ 
  Isolation isolation() default Isolation.DEFAULT; 
 
  /** 
   * The timeout for this transaction. 
   * Defaults to the default timeout of the underlying transaction system. 
   * @see org.springframework.transaction.interceptor.TransactionAttribute#getTimeout() 
   */ 
  int timeout() default TransactionDefinition.TIMEOUT_DEFAULT; 
 
  /** 
   * {@code true} if the transaction is read-only. 
   * Defaults to {@code false}. 
   * <p>This just serves as a hint for the actual transaction subsystem; 
   * it will <i>not necessarily</i> cause failure of write access attempts. 
   * A transaction manager which cannot interpret the read-only hint will 
   * <i>not</i> throw an exception when asked for a read-only transaction. 
   * @see org.springframework.transaction.interceptor.TransactionAttribute#isReadOnly() 
   */ 
  boolean readOnly() default false; 
 
  /** 
   * Defines zero (0) or more exception {@link Class classes}, which must be a 
   * subclass of {@link Throwable}, indicating which exception types must cause 
   * a transaction rollback. 
   * <p>This is the preferred way to construct a rollback rule, matching the 
   * exception class and subclasses. 
   * <p>Similar to {@link org.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(Class clazz)} 
   */ 
  Class<? extends Throwable>[] rollbackFor() default {}; 
 
  /** 
   * Defines zero (0) or more exception names (for exceptions which must be a 
   * subclass of {@link Throwable}), indicating which exception types must cause 
   * a transaction rollback. 
   * <p>This can be a substring, with no wildcard support at present. 
   * A value of "ServletException" would match 
   * {@link javax.servlet.ServletException} and subclasses, for example. 
   * <p><b>NB: </b>Consider carefully how specific the pattern is, and whether 
   * to include package information (which isn't mandatory). For example, 
   * "Exception" will match nearly anything, and will probably hide other rules. 
   * "java.lang.Exception" would be correct if "Exception" was meant to define 
   * a rule for all checked exceptions. With more unusual {@link Exception} 
   * names such as "BaseBusinessException" there is no need to use a FQN. 
   * <p>Similar to {@link org.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(String exceptionName)} 
   */ 
  String[] rollbackForClassName() default {}; 
 
  /** 
   * Defines zero (0) or more exception {@link Class Classes}, which must be a 
   * subclass of {@link Throwable}, indicating which exception types must <b>not</b> 
   * cause a transaction rollback. 
   * <p>This is the preferred way to construct a rollback rule, matching the 
   * exception class and subclasses. 
   * <p>Similar to {@link org.springframework.transaction.interceptor.NoRollbackRuleAttribute#NoRollbackRuleAttribute(Class clazz)} 
   */ 
  Class<? extends Throwable>[] noRollbackFor() default {}; 
 
  /** 
   * Defines zero (0) or more exception names (for exceptions which must be a 
   * subclass of {@link Throwable}) indicating which exception types must <b>not</b> 
   * cause a transaction rollback. 
   * <p>See the description of {@link #rollbackForClassName()} for more info on how 
   * the specified names are treated. 
   * <p>Similar to {@link org.springframework.transaction.interceptor.NoRollbackRuleAttribute#NoRollbackRuleAttribute(String exceptionName)} 
   */ 
  String[] noRollbackForClassName() default {}; 
 
} 

Based on the source code, we can see that at @Transactional, there are so many properties that can be configured for complex application control purposes. The usage and function of each attribute will be explained and explained one by one later in this article.

2. Use the Spring configuration at @Transactional

To use @Transactional-based transaction management, you need to configure Spring as follows:


 <beans:bean id="transactionManager" 
  class="org.springframework.orm.jpa.JpaTransactionManager"> 
  <beans:property name="dataSource" ref="dataSource" /> 
  <beans:property name="entityManagerFactory" ref="entityManagerFactory" /> 
</beans:bean> 
 
<!--  Declare using annotated transactions  --> 
<tx:annotation-driven transaction-manager="transactionManager" /> 

dataSource is defined in Spring configuration file data source object instance, EntityManagerFactory is based on the JPA use entity class manager: org. springframework. orm. jpa. LocalContainerEntityManagerFactoryBean. These are used to configure connection information to the database. Essentially, @Transactional USES JDBC's transactions for transaction control.

< annotation-driven > The tag declaration is to enable @Transactional within Spring for transaction management, declarations such as switches.

3. @ Transactional value

value is mainly used here to specify different transaction managers; It is mainly used to satisfy that there are different transaction managers in the same system. For example, in Spring, two transaction managers, txManager1 and txManager2, are declared.

This parameter can then be used by the user to specify a specific txManager as needed.

What if there are multiple transaction managers? For example, in a system that requires access to multiple data sources or databases, multiple transaction managers must be configured.

4. @ Transactional propagation

Propagation supports seven different communication mechanisms:

REQUIRED

The e business method needs to run in a transaction, if the method is already in a transaction when it runs, then join the transaction, or create a new transaction yourself, which is the default propagation behavior of spring.

SUPPORTS:

If a business method is invoked within the scope of a transaction, the method becomes part 1 of the transaction, and if the business method is invoked outside the scope of a transaction, the method executes in a non-transactional environment.

MANDATORY:

Can only be executed within an existing transaction, business methods cannot initiate their own transaction, and if the business method is called in an environment without a transaction, an exception is thrown

REQUIRES_NEW

A business method always initiates a new transaction for itself. If the method is already running in a transaction, the original transaction is suspended and the new transaction is created. The new transaction is not completed until the method is finished and the original transaction is resumed.

NOT_SUPPORTED

Declare that a method requires a transaction, and if the method is not associated with a transaction, the container does not open a transaction for it. If the method is invoked in a transaction, the transaction is suspended and the original transaction resumes execution after the method invocation.

NEVER:

Declare that methods must not be executed within the scope of a transaction. If a method is executed within the scope of a transaction, the container throws an exception.

NESTED:

Exists if one active transaction, it is running in a nested transaction. If there is no transaction, then the REQUIRED properties. It USES a single transaction, the transaction can have multiple rollback point of guarantee. Internal transaction rollback will not affect the external affairs, it is only right DataSourceTransactionManager transaction manager work.

In fact, the most confusing thing is that REQUIRED_NEW and NESTED are two different communication mechanisms with similar functions, both of which involve transaction nesting. What's the difference between them? How do you use these two patterns correctly?

Here is an excerpt from the Spring document:


  PROPAGATION_REQUIRES_NEW : uses a completely independent transaction for
 each affected transaction scope. In that case, the underlying physical 
transactions are different and hence can commit or roll back independently, 
with an outer transaction not affected by an inner transaction's rollback status.

Internal transactions run independently and can be rolled back or committed independently within their respective scopes. External transactions will not be affected by the rollback state of internal transactions.


 ROPAGATION_NESTED : uses a single physical transaction with multiple 
savepoints that it can roll back to. Such partial rollbacks allow an
 inner transaction scope to trigger a rollback for its scope, with the outer 
transaction being able to continue the physical transaction despite some operations 
having been rolled back. This setting is typically mapped onto JDBC savepoints, so will 
only work with JDBC resource transactions.

NESTED's transactions, managed based on single 1 transactions, provide multiple savepoints. This multiple savepoint mechanism allows changes in an internal transaction to trigger a rollback of an external transaction. An external transaction can continue to process after it has been rolled, even if part of the operation has been rolled. Since this setting is based on JDBC's savepoint, it can only work in JDBC's mechanistic IQ.

Therefore, both of them are nested transactions. The difference lies in whether there is influence between internal and external transactions. A partial rollback occurs between NESTED, which is affected, while REQUIRED_NEW is independent.

Thank you for reading, I hope to help you, thank you for your support to this site!


Related articles: