Транзакция — это последовательность операций, которые выполняются как единое целое. Если одна из операций не выполнится, все изменения отменяются. Например:
Если на складе не хватает товара, заказ тоже не должен быть создан. В этом и заключается суть транзакций.
@Transactional
?Когда вы добавляете аннотацию @Transactional
к методу, Spring создаёт прокси, который управляет транзакцией. Вот как это работает:
Допустим, вы пишете сервис для создания пользователей:
@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Transactional
public void createUser(String name, String email) {
User user = new User();
user.setName(name);
user.setEmail(email);
userRepository.save(user);
if (email.contains("@example.com")) {
throw new IllegalArgumentException("Email not allowed: " + email);
}
}
}
- Если email
содержит @example.com
, метод выбросит исключение, и данные в базе откатятся.
- Если ошибок нет, пользователь сохранится в базе.
Аннотация @Transactional поддерживает множество параметров:
Определяет, как текущая транзакция взаимодействует с существующими транзакциями. Основные значения:
REQUIRED (по умолчанию) — если транзакция уже существует, метод использует её; если нет, создаётся новая.
REQUIRES_NEW — всегда создаёт новую транзакцию, независимо от существующих.
SUPPORTS — если транзакция существует, метод использует её; если нет, выполняется без транзакции.
Задаёт уровень изоляции транзакции. Например:
READ_UNCOMMITTED — предотвращает чтение данных которые не были подтверждены другой транзакцией (данный уровень изоляции не поддерживается ORACLE и PostgreSQL).
READ_COMMITTED (по умолчанию) — предотвращает чтение неподтверждённых данных (существует фантомное и неповторяющееся чтение).
REPEATABLE_READ — в данном уровне изоляции существует только фантомное чтение.
SERIALIZABLE — обеспечивает максимальную изоляцию, но снижает производительность.
Указывает максимальное время выполнения транзакции. Если время превышено, транзакция откатывается.
@Transactional(timeout = 5) // транзакция завершится, если выполнение превысит 5 секунд
public void performLongTask() {
// Долгое выполнение
}
Указывает, при каких исключениях следует откатывать транзакцию.
@Transactional(rollbackFor = CustomException.class)
public void performTask() throws CustomException {
// Код
}
Используется для оптимизации операций только для чтения. Например, при чтении данных из базы:
@Transactional(readOnly = true)
public List getAllUsers() {
return userRepository.findAll();
}
Spring использует прокси для управления транзакциями, и вызов метода с @Transactional изнутри того же класса обходит этот механизм. В результате транзакция не создаётся.
@Service
public class UserService {
@Transactional
public void methodA() {
// транзакция создаётся
}
public void methodB() {
methodA(); // транзакция НЕ активируется
}
}
Вынесите транзакционный метод в отдельный компонент или вызовите его через Spring-контекст.
По умолчанию транзакция откатывается только при исключениях, наследующихся от RuntimeException
. Если вы выбрасываете checked-исключение (например, IOException
), транзакция не откатится.
@Transactional
public void performTask() throws IOException {
// код
throw new IOException("Ошибка");
}
Почему это происходит: Spring настроен откатывать только unchecked исключения для совместимости с JPA.
@Transactional(rollbackFor = IOException.class)
public void performTask() throws IOException {
// код
}
Если транзакция открыта слишком долго (например, во время работы с внешним API), это может вызвать блокировки базы данных.
@Transactional
public void longOperation() {
userRepository.save(new User());
externalApiCall(); // долгий вызов
}
Почему это происходит: Транзакция блокирует ресурсы базы данных до её завершения.
public void longOperation() {
userRepository.save(new User());
callExternalApi(); // без транзакции
}
readOnly = true
, чтобы ускорить выполнение методов, которые только читают данные.timeout
.rollbackFor
, чтобы откатывать транзакцию при checked исключениях.Аннотация @Transactional
— это удобный инструмент для управления транзакциями в Spring Boot. Она помогает избежать ошибок в работе с базой данных и сохраняет код чистым. Но важно знать, как она работает, и избегать частых ошибок.
Если вам понравилась статья, подписывайтесь на Telegram-канал JavaCraft.ru. Там вы найдёте ещё больше простых и полезных материалов!
Вы должны войти в систему, чтобы оставить комментарий.