Понимание управления транзакциями в Spring Boot

Управление транзакциями в Spring Boot имеет решающее значение для обеспечения целостности и согласованности данных в ваших приложениях. Менеджер транзакций играет ключевую роль в управлении транзакциями. Вот что вам нужно знать:

Роль TransactionManager

Когда вызывается метод, помеченный @Transactional, Spring Boot использует TransactionManager для создания транзакции или присоединения к ней. Менеджер транзакций контролирует жизненный цикл транзакции, включая ее фиксацию или откат в зависимости от результата операции.

Уровни изоляции транзакций

Spring Boot поддерживает различные уровни изоляции транзакций, включая READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ и SERIALIZABLE. Эти уровни определяют, как транзакции взаимодействуют друг с другом и с базовыми данными. Выберите правильный уровень изоляции для нужд вашего приложения.

@Service
public class UserService {
  @Autowired
  private UserRepository userRepository;
jj@Transactional
  public void updateUser(String username, String email) {
    User user = userRepository.findByUsername(username);
    user.setEmail(email);
    // ... other operations
  }
}

В приведенном выше примере updateUser() отмечен @Transactional, что позволяет Spring Boot управлять поведением транзакции.

Понимание распространения транзакций

Транзакционное поведение может варьироваться в зависимости от того, как аннотируются методы. Вот ключевое различие:

@Transactional или @Transactional(распространение = Propagation.REQUIRES_NEW)

  • @Transactional создает транзакцию или присоединяется к ней.
  • @Transactional(propagation = Propagation.REQUIRES_NEW) создает новую транзакцию, приостанавливая текущую, если она существует.
@Service
public class MyService {
@Transactional
    public void methodA() {
        // ... some code here
        methodB();
        // ... some code here
    }
@Transactional(propagation = Propagation.REQUIRES_NEW)
    public void methodB() {
        // ... some code here
    }
}

В этом примере methodA() вызывает methodB(). Транзакция methodA() приостанавливается, когда methodB() начинает новую транзакцию из-за настройки распространения REQUIRES_NEW.

Обработка транзакций внутри одного класса

Примечательно поведение Spring по умолчанию, когда метод @Transactional вызывает другой метод @Transactional в том же классе:

Поведение по умолчанию

По умолчанию Spring использует подход «на основе прокси». Если метод @Transactional вызывает другой метод @Transactional в том же классе, транзакционное поведение не применяется.

@Service
public class MyService {
    @Autowired
    private MyService self;
ja   @Transactional
    public void methodA() {
        // ... some code here
        self.methodB();
        // ... some code here
    }
@Transactional
    public void methodB() {
        // ... some code here
    }
}

В этом примере methodA() и methodB() отмечены @Transactional. Однако из-за подхода, основанного на прокси-сервере, транзакционное поведение не применяется к methodB() при вызове из methodA(). Чтобы решить эту проблему, рассмотрите возможность переплетения на основе AspectJ или переноса метода @Transactional в отдельный класс.

Управление транзакциями между различными компонентами

При вызове метода в другом компоненте Spring создает новый прокси вокруг целевого компонента, позволяя ему управлять транзакционным поведением:

@Service
public class MyService {
@Autowired
    private OtherService otherService;
@Transactional
    public void methodA() {
        // ... some code here
        otherService.methodB();
        // ... some code here
    }
}
@Service
public class OtherService {
   @Transactional
    public void methodB() {
        // ... some code here
    }
}

В этом примере methodA() вызывает methodB() на другом компоненте (OtherService). Spring создает новый прокси вокруг OtherService для применения транзакционного поведения на основе настроек methodA()Propagation.

Обработка непроверенных исключений

Когда метод @Transactional выдает непроверенное исключение, Spring автоматически откатывает транзакцию по умолчанию. Это гарантирует, что изменения данных внутри транзакции не сохранятся в случае возникновения ошибки.

@Service
@Transactional
public class UserService {
 @Autowired
  private UserRepository userRepository;
 public void updateUser(String username, String email) {
    User user = userRepository.findByUsername(username);
    if (user == null) {
      throw new RuntimeException("User not found");
    }
    user.setEmail(email);
    userRepository.save(user);
    throw new RuntimeException("Something went wrong");
  }
}

В этом примере updateUser() отмечен @Transactional и выдает непроверяемое исключение. По умолчанию транзакция будет отменена, отменяя изменения, внесенные в адрес электронной почты пользователя.

Настройка поведения отката

Вы можете настроить поведение отката, используя свойства rollbackFor или noRollbackFor аннотации @Transactional.

@Service
@Transactional(noRollbackFor = RuntimeException.class)
public class UserService { 
// ...
}

В этом примере мы указываем, что RuntimeException не должен вызывать откат. Это может быть полезно, если вы хотите сохранить изменения в транзакции, даже если произойдет ошибка.

Поведение отката по умолчанию

По умолчанию метод @Transactional откатывает транзакцию при любом непроверенном исключении. Настройте это поведение, используя свойства rollbackFor или noRollbackFor.

Частные методы и @Transactional

@Transactional работает только с общедоступными методами. Spring создает прокси вокруг общедоступных методов для управления транзакционным поведением. Частные методы не видны прокси-серверу и не могут быть обернуты в контекст транзакции.

@Service
public class MyService {
   @Transactional
    public void methodA() {
        // ... some code here
        methodB();
        // ... some code here
    }
    private void methodB() {
        // ... some code here
    }
}

В этом примере methodA() отмечен @Transactional, а methodB() — нет. Чтобы включить транзакционное поведение для methodB(), сделайте его общедоступным или переместите аннотацию @Transactional в метод, который вызывает и methodA(), и methodB().

Обработка проблем параллелизма

Аннотация Spring Boot @Transactional предоставляет механизм для решения проблем параллелизма путем сериализации транзакций. Уровень изоляции по умолчанию предотвращает большинство проблем параллелизма, гарантируя, что транзакции не мешают друг другу.

@Service
public class UserService {
  @Autowired
  private UserRepository userRepository;
 @Transactional
  public void updateUser(String username, String email) {
    User user = userRepository.findByUsername(username);
    user.setEmail(email);
    // ... other operations
  }
}

В этом примере updateUser() отмечен @Transactional, и Spring гарантирует сериализацию транзакций, когда несколько потоков пытаются одновременно изменить адрес электронной почты одного и того же пользователя. Это предотвращает несогласованность данных и состояния гонки.

Помните, что уровень изоляции по умолчанию, используемый @Transactional в Spring, равен Isolation.DEFAULT, что соответствует значению по умолчанию базового источника данных. Обычно это приводит к изоляции «завершения чтения», которая подходит для большинства баз данных.

Освоение @Transactional имеет решающее значение для эффективного управления транзакциями в приложениях Spring Boot. Эти лучшие практики помогут вам выполнять транзакции уверенно и точно.

Понравилась эта статья?

Если вам понравилось читать этот пост, вы получили от него помощь, знания и хотите поддержать мои усилия, пожалуйста, хлопайте в ладоши этой статье и подписывайтесь.
Первоначально опубликовано на blog.anilgulati.tech
Нажмите Здесь, чтобы подписаться на дополнительную информацию
Чтобы узнать больше о моих работах, посетите мое портфолио на anilgulati.tech.

Спасибо, что дочитали до конца. Пожалуйста, подумайте о том, чтобы подписаться на автора и эту публикацию. Посетите Stackademic, чтобы узнать больше о том, как мы демократизируем бесплатное образование в области программирования во всем мире.