English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Detailed Explanation of Spring Boot Transaction Management

Implement the interface PlatformTransactionManager in Spring Boot transaction management.

public interface PlatformTransactionManager {
  org.springframework.transaction.TransactionStatus getTransaction(org.springframework.transaction.TransactionDefinition transactionDefinition) throws org.springframework.transaction.TransactionException;
  void commit(org.springframework.transaction.TransactionStatus transactionStatus) throws org.springframework.transaction.TransactionException;
  void rollback(org.springframework.transaction.TransactionStatus transactionStatus) throws org.springframework.transaction.TransactionException;
}

When we use spring-boot-starter-When using JDBC dependencies, the framework will automatically default inject DataSourceTransactionManager. Therefore, we do not need any additional configuration to use the @Transactional annotation for transaction usage.

JDBC transaction manager

In the Service, methods annotated with @Transactional will support transactions. If the annotation is on the class, all methods in the class will support transactions by default.

Multiple transaction managers

First: you can implement the TransactionManagementConfigurer interface, and the return value of the method inside is the default transaction manager.

Second: you can set the value on the specific execution method.

If there are multiple PlatformTransactionManager instances in the Spring container and no default value is specified by implementing the interface TransactionManagementConfigurer, when we use the annotation @Transactional on a method, we must specify the value. If not specified, an exception will be thrown.

//@EnableTransactionManagement // Enables annotation-based transaction management, equivalent to <tx:annotation> in XML configuration files.-driven />
@SpringBootApplication
public class ProfiledemoApplication implements TransactionManagementConfigurer {
  @Resource(name="txManager2}
  private PlatformTransactionManager txManager2;
  // Manually create a transaction manager1 the datasource framework will be automatically injected
  //In the Spring container, manually annotated @Bean will be loaded first, and the framework will not instantiate other PlatformTransactionManager implementation classes.
  @Bean(name = "txManager1}
  public PlatformTransactionManager txManager(DataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
  }
  // Create a transaction manager2
  @Bean(name = "txManager2}
  public PlatformTransactionManager txManager2(EntityManagerFactory factory) {
    return new JpaTransactionManager(factory);
  }
  // Implement the TransactionManagementConfigurer interface method, whose return value represents the default transaction manager to use when there are multiple transaction managers
  @Override
  public PlatformTransactionManager annotationDrivenTransactionManager() {
    return txManager2;
  }
  public static void main(String[] args) {
    SpringApplication.run(ProfiledemoApplication.class, args);
  }
}

specific implementation

@Component
public class DevSendMessage implements SendMessage {
  // to specifically specify which transaction manager to use
  @Transactional(value="txManager1}
  @Override
  public void send() {
    System.out.println(">>>>>>>>Dev Send()<<<<<<<<");
    send2();
  }
  @Transactional
  public void send2()) {
    System.out.println(">>>>>>>>Dev Send2()<<<<<<<<");
  }
}

Isolation level

public enum Isolation {
  DEFAULT(TransactionDefinition.ISOLATION_DEFAULT),
  READ_UNCOMMITTED(TransactionDefinition.ISOLATION_READ_UNCOMMITTED),
  READ_COMMITTED(TransactionDefinition.ISOLATION_READ_COMMITTED),
  REPEATABLE_READ(TransactionDefinition.ISOLATION_REPEATABLE_READ),
  SERIALIZABLE(TransactionDefinition.ISOLATION_SERIALIZABLE);
  private final int value;
  Isolation(int value) { this.value = value; }
  public int value() { return this.value; }
}
  1. DEFAULT: This is the default value, indicating that the default isolation level of the underlying database is used. For most databases, this value is usually: READ_COMMITTED.
  2. READ_UNCOMMITTED: This isolation level indicates that a transaction can read the data that has been modified by another transaction but has not yet been committed. This level cannot prevent dirty reads and non-repeatable reads, so this isolation level is rarely used.
  3. READ_COMMITTED: This isolation level indicates that a transaction can only read the data that has been committed by another transaction. This level can prevent dirty reads and is the recommended value in most cases.
  4. REPEATABLE_READ: This isolation level indicates that a transaction can repeatedly execute a query multiple times throughout the process, and each time it returns the same records. Even if there are new data that meet the query between multiple queries, these new records will be ignored. This level can prevent dirty reads and non-repeatable reads.
  5. SERIALIZABLE: All transactions are executed sequentially one by one, so there is no interference between transactions at all. That is to say, this level can prevent dirty reads, non-repeatable reads, and phantom reads. However, this will seriously affect the performance of the program. This level is usually not used.

Specify method: By using the isolation attribute setting, for example:

@Transactional(isolation = Isolation.DEFAULT)

Propagation behavior

The propagation behavior of a transaction refers to the fact that if a transaction context already exists before the current transaction begins, there are several options to specify the execution behavior of a transactional method.

We can see that the org.springframework.transaction.annotation.Propagation enumeration class defines6an enumeration value representing the propagation behavior:

public enum Propagation {
  REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),
  SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),
  MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),
  REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),
  NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),
  NEVER(TransactionDefinition.PROPAGATION_NEVER),
  NESTED(TransactionDefinition.PROPAGATION_NESTED);
  private final int value;
  Propagation(int value) { this.value = value; }
  public int value() { return this.value; }
}

REQUIRED: If a transaction exists, join the transaction; if no transaction exists, create a new transaction. Default value.

SUPPORTS: If a transaction exists, join the transaction; if no transaction exists, continue to run in non-transactional mode.

MANDATORY: If a transaction exists, join the transaction; if no transaction exists, throw an exception. (Forced into the transaction)

REQUIRES_NEW: Create a new transaction, and if a transaction exists, suspend the current transaction. (Commonly used for logging, even if the transaction rolls back, this transaction will still execute and record error information)

NOT_SUPPORTED: Run in non-transactional mode, and if a transaction exists, suspend the current transaction.

NEVER: Run in non-transactional mode, and if a transaction exists, throw an exception.

NESTED: If a transaction exists currently, run a nested transaction as the current transaction; if no transaction exists, this value is equivalent to REQUIRED.

Specify the method: By using the propagation attribute to set, for example:

@Transactional(propagation = Propagation.REQUIRED)

Cases where the transaction does not rollback

Only rollback when a RuntimeException that is not caught occurs

catch the exception thrown, both insertions will succeed

@Override
  @Transactional
  public void insertandinsert(Staff staff) {
    staffDao.insert(staff);
    try {
      int i = 1 / 0;
    }
      e.printStackTrace();
    }
    staffDao.insert(staff);
  }

Add the statement TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); in the catch statement of the method in the service layer to manually rollback and not insert data

@Override
  @Transactional
  public void insertandinsert(Staff staff) throws Exception {
    try {
      staffDao.insert(staff);
      int i=1/0;
      staffDao.insert(staff);
    }
      TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }
  }

That's all for this article. I hope it will be helpful to everyone's learning and also hope everyone will support the Yelling Tutorial more.

Statement: The content of this article is from the network, and the copyright belongs to the original author. The content is contributed and uploaded by Internet users spontaneously. This website does not own the copyright, has not been manually edited, and does not assume relevant legal liability. If you find any content suspected of copyright infringement, please send an email to: notice#oldtoolbag.com (Please replace # with @ when sending an email to report violations, and provide relevant evidence. Once verified, this site will immediately delete the content suspected of infringement.)

You May Also Like