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

Объяснение управления транзакциями в Springboot

В управлении транзакциями Spring Boot реализуется интерфейс PlatformTransactionManager.

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;
}

Когда мы используем зависимость spring-boot-starter-jdbc,框架 автоматически инъектирует DataSourceTransactionManager по умолчанию. Поэтому нам не нужно никакого дополнительного конфигурирования, чтобы использовать транзакцию с помощью аннотации @Transactional.

Менеджер транзакций JDBC

В Service, метод, помеченный аннотацией @Transactional, будет поддерживать транзакцию. Если аннотация находится на классе, то все методы класса по умолчанию поддерживают транзакцию.

Ситуация с несколькими менеджерами транзакций

Первый: можно реализовать интерфейс TransactionManagementConfigurer, где метод возвращает значение по умолчанию для управления транзакциями.

Второй: можно установить value на конкретном методе выполнения

Если в контейнере Spring существует несколько экземпляров PlatformTransactionManager и не реализован интерфейс TransactionManagementConfigurer для указания значения по умолчанию, при использовании аннотации @Transactional в методе, необходимо указать value, если не указать,则会 выбросить исключение.

// @EnableTransactionManagement // Включение аннотации управления транзакциями, эквивалент xml конфигурации <tx:annotation-driven />
@SpringBootApplication
public class ProfiledemoApplication implements TransactionManagementConfigurer {
  @Resource(name="txManager2")
  private PlatformTransactionManager txManager2;
  // Ручное создание менеджера транзакций 1, datasource框架 будет автоматически инъектировать
  // В контейнере Spring, мы вручную аннотируем @Bean, и его будут загружены первыми,框架 не будет реинциализировать другие реализации PlatformTransactionManager.
  @Bean(name = "txManager1")
  public PlatformTransactionManager txManager(DataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
  }
  // Создание менеджера транзакций 2
  @Bean(name = "txManager2")
  public PlatformTransactionManager txManager2(EntityManagerFactory factory) {
    return new JpaTransactionManager(factory);
  }
  // Реализация интерфейса TransactionManagementConfigurer, его возвращаемое значение представляет собой defaultManager для использования в случае наличия нескольких менеджеров транзакций
  @Override
  public PlatformTransactionManager annotationDrivenTransactionManager() {
    return txManager2;
  }
  public static void main(String[] args) {
    SpringApplication.run(ProfiledemoApplication.class, args);
  }
}

Конкретная реализация

@Component
public class DevSendMessage implements SendMessage {
  // Использование value для конкретного указания использования определенного менеджера транзакций
  @Transactional(value="txManager1")
  @Override
  public void send() {
    System.out.println(">>>>>>>>Dev Send()<<<<<<<<");
    send2();
  }
  @Transactional
  public void send2() {
    System.out.println(">>>>>>>>Dev Send2()<<<<<<<<");
  }
}

Изоляция уровня

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: это значение по умолчанию, которое означает использование уровня изоляции по умолчанию базового数据库. Для большинства баз данных это значение обычно равно: READ_COMMITTED.
  2. READ_UNCOMMITTED: этот уровень изоляции означает, что транзакция может читать данные, которые были изменены другой транзакцией, но еще не подтверждены. Этот уровень изоляции не может предотвратить чтение мусора и повторное чтение, поэтому rarely используется.
  3. READ_COMMITTED: этот уровень изоляции означает, что транзакция может читать только данные, которые уже были подтверждены другой транзакцией. Этот уровень изоляции может предотвратить чтение мусора и является рекомендованным значением в большинстве случаев.
  4. REPEATABLE_READ: этот уровень изоляции означает, что транзакция может повторно выполнять определенный запрос несколько раз в процессе транзакции, и каждый раз возвращаемые записи будут одинаковыми. Даже если между несколькими запросами будут добавлены новые данные, которые соответствуют этому запросу, эти новые записи будут пропущены. Этот уровень изоляции может предотвратить чтение мусора и неповторимое чтение.
  5. SERIALIZABLE: все транзакции выполняются по порядку, один за другим, таким образом, между транзакциями полностью исключается взаимное влияние, то есть, на этом уровне можно предотвратить чтение мусора, неповторимое чтение и фантасмагорическое чтение. Однако это严重影响 производительность программы. Обычно этот уровень не используется.

Определение метода: через использование свойства isolation, например:

@Transactional(isolation = Isolation.DEFAULT)

Поведение передачи

Под поведением передачи транзакции понимается, что если до начала текущей транзакции уже существует контекст транзакции, то в этом случае есть несколько вариантов для определения поведения выполнения метода транзакции.

Мы можем увидеть, что в классе枚举 org.springframework.transaction.annotation.Propagation определены 6 значений, представляющих поведение передачи:

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: если текущая транзакция существует, то добавляется к этой транзакции; если текущей транзакции нет, то создается новая транзакция. Значение по умолчанию.

SUPPORTS: если текущая транзакция существует, то добавляется к этой транзакции; если текущей транзакции нет, то продолжает работать в не транзакционном режиме.

MANDATORY: если текущая транзакция существует, то добавляется к этой транзакции; если текущей транзакции нет, то выбрасывается исключение (принудительно добавляется в транзакцию)

REQUIRES_NEW: создает новую транзакцию, если текущая транзакция существует, то текущую транзакцию приостанавливается (часто используется для записи журнала, даже если перед этим произошел откат, транзакция все равно будет выполнена, чтобы записать информацию об ошибке)

NOT_SUPPORTED: выполняется в не транзакционном режиме, если текущая транзакция существует, то текущую транзакцию приостанавливается.

NEVER: выполняется в не транзакционном режиме, если текущая транзакция существует, то выбрасывается исключение.

NESTED: если текущая транзакция существует, то создается транзакция в качестве вложенной транзакции текущей транзакции для выполнения; если текущей транзакции нет, то это значение эквивалентно REQUIRED.

Указанный метод: с помощью установки атрибута propagation, например:

@Transactional(propagation = Propagation.REQUIRED)

Ситуации, когда транзакция не будет откатываться

Р rolling back только в случае возникновения не捕获ленного RuntimeException

catch-вызванные исключения, оба вставки будут успешными

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

В блоке catch метода уровня service добавьте предложение: TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); для ręcznego cofnięcia, что не позволит вставить данные

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

Это конец статьи, надеюсь, она поможет вам в изучении, также希望大家多多支持呐喊教程。

Заявление: содержимое этой статьи взято из Интернета, авторские права принадлежат соответствующему автору. Контент предоставлен пользователями Интернета, самостоятельно загружен, сайт не обладает правами собственности, не был отредактирован вручную и не несет ответственности за связанные с этим юридические вопросы. Если вы обнаружите материалы,涉嫌侵犯版权, пожалуйста, отправьте письмо по адресу: notice#oldtoolbag.com (во время отправки письма замените # на @), чтобы сообщить о нарушении, и предоставьте соответствующие доказательства. Если факт будет подтвержден, сайт немедленно удалил涉嫌侵权的内容.

Основной учебник
Рекомендуем