Понимание управления транзакциями в 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, чтобы узнать больше о том, как мы демократизируем бесплатное образование в области программирования во всем мире.