JAVAPROGLIB Telegram 6471
⚙️ Как корректно работать с @Transactional в Spring

Аннотация @Transactional — мощный инструмент, но ее неправильное использование может привести к незаметным, но критическим ошибкам: потерянные данные, неожиданные откаты или вовсе отсутствие транзакции. Разбираем частые ошибки и их решения.

@Transactional в том же классе

Если вызываете транзакционный метод внутри того же класса (this.method()), Spring-прокси не срабатывает, и транзакция не создается.
@Service
public class OrderService {

@Transactional
public void createOrder() {
saveOrder(); // Вызов внутреннего метода - транзакция НЕ создается!
}

private void saveOrder() {
// Сохранение заказа
}
}


— Решение: вынести метод в другой Spring-бин.

@Transactional в private-методах

Spring AOP работает через прокси, а прокси не видит private-методы. В результате @Transactional в таких методах просто игнорируется.
@Transactional
private void saveData() { // Транзакция НЕ будет работать!
repository.save(entity);
}


— Решение: метод должен быть public и вызываться через другой Spring-бин

Неправильный выбор Propagation

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

— REQUIRED использует текущую транзакцию, если она есть, иначе создаёт новую.
— REQUIRES_NEW всегда создаёт новую транзакцию, независимо от текущей (может привести к неожиданным коммитам).
— NESTED создаёт вложенную транзакцию, которая откатывается отдельно от родительской.
— SUPPORTS использует существующую транзакцию, но не требует её (если транзакции нет, работает без неё).
— NOT_SUPPORTED выполняет код вне транзакции, даже если она уже существует.
— NEVER гарантирует, что код выполняется только вне транзакции, иначе выбрасывает исключение.
— MANDATORY требует, чтобы код выполнялся внутри уже существующей транзакции, иначе выбрасывает исключение.

Откат только по CheckedException

Spring по умолчанию откатывает транзакции только при RuntimeException, а CheckedException (например, SQLException) его не прерывает. Однако изменение этого поведения требует осторожности.
@Transactional
public void updateUser() throws IOException { // CheckedException не откатит транзакцию!
userRepository.save(user);
throw new IOException("Ошибка ввода-вывода");
}


— Решение: указать rollbackFor = Exception.class, если хотите откатывать и CheckedException.

@Transactional в контроллере

Spring сначала коммитит транзакцию, а потом отправляет HTTP-ответ. Если после коммита возникнет ошибка (например, сеть упала), клиент может получить 500, но изменения уже сохранены.

— Решение: транзакции должны быть в сервисах, а не в контроллерах.

💬 Какие проблемы с @Transactional встречались в практике?

🐸 Библиотека джависта #буст
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14🔥121❤‍🔥1😁1



tgoop.com/javaproglib/6471
Create:
Last Update:

⚙️ Как корректно работать с @Transactional в Spring

Аннотация @Transactional — мощный инструмент, но ее неправильное использование может привести к незаметным, но критическим ошибкам: потерянные данные, неожиданные откаты или вовсе отсутствие транзакции. Разбираем частые ошибки и их решения.

@Transactional в том же классе

Если вызываете транзакционный метод внутри того же класса (this.method()), Spring-прокси не срабатывает, и транзакция не создается.

@Service
public class OrderService {

@Transactional
public void createOrder() {
saveOrder(); // Вызов внутреннего метода - транзакция НЕ создается!
}

private void saveOrder() {
// Сохранение заказа
}
}


— Решение: вынести метод в другой Spring-бин.

@Transactional в private-методах

Spring AOP работает через прокси, а прокси не видит private-методы. В результате @Transactional в таких методах просто игнорируется.
@Transactional
private void saveData() { // Транзакция НЕ будет работать!
repository.save(entity);
}


— Решение: метод должен быть public и вызываться через другой Spring-бин

Неправильный выбор Propagation

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

— REQUIRED использует текущую транзакцию, если она есть, иначе создаёт новую.
— REQUIRES_NEW всегда создаёт новую транзакцию, независимо от текущей (может привести к неожиданным коммитам).
— NESTED создаёт вложенную транзакцию, которая откатывается отдельно от родительской.
— SUPPORTS использует существующую транзакцию, но не требует её (если транзакции нет, работает без неё).
— NOT_SUPPORTED выполняет код вне транзакции, даже если она уже существует.
— NEVER гарантирует, что код выполняется только вне транзакции, иначе выбрасывает исключение.
— MANDATORY требует, чтобы код выполнялся внутри уже существующей транзакции, иначе выбрасывает исключение.

Откат только по CheckedException

Spring по умолчанию откатывает транзакции только при RuntimeException, а CheckedException (например, SQLException) его не прерывает. Однако изменение этого поведения требует осторожности.
@Transactional
public void updateUser() throws IOException { // CheckedException не откатит транзакцию!
userRepository.save(user);
throw new IOException("Ошибка ввода-вывода");
}


— Решение: указать rollbackFor = Exception.class, если хотите откатывать и CheckedException.

@Transactional в контроллере

Spring сначала коммитит транзакцию, а потом отправляет HTTP-ответ. Если после коммита возникнет ошибка (например, сеть упала), клиент может получить 500, но изменения уже сохранены.

— Решение: транзакции должны быть в сервисах, а не в контроллерах.

💬 Какие проблемы с @Transactional встречались в практике?

🐸 Библиотека джависта #буст

BY Библиотека джависта | Java, Spring, Maven, Hibernate




Share with your friend now:
tgoop.com/javaproglib/6471

View MORE
Open in Telegram


Telegram News

Date: |

How to create a business channel on Telegram? (Tutorial) Step-by-step tutorial on desktop: The group’s featured image is of a Pepe frog yelling, often referred to as the “REEEEEEE” meme. Pepe the Frog was created back in 2005 by Matt Furie and has since become an internet symbol for meme culture and “degen” culture. How to Create a Private or Public Channel on Telegram? Read now
from us


Telegram Библиотека джависта | Java, Spring, Maven, Hibernate
FROM American