Spring транзакция REQUIRED vs REQUIRES_NEW: откат транзакции
У меня есть метод, который имеет свойство транзакции propagation = Propagation.REQUIRES_NEW
:
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void createUser(final UserBean userBean) {
//Some logic here that requires modification in DB
}
Этот метод можно вызывать несколько раз одновременно и для каждой транзакции, если возникает ошибка, чем она откатывается (независимо от других транзакций).
Проблема заключается в том, что это может заставить Spring создавать несколько транзакций, даже если они доступны, и могут вызвать некоторые проблемы с производительностью.
Java doc propagation = Propagation.REQUIRED
говорит: Support a current transaction, create a new one if none exists.
Это, похоже, решает проблему производительности, не так ли?
Как насчет проблемы с откатом? Что делать, если вызов нового метода откатывается при использовании существующей транзакции? не будет ли откат всей транзакции даже предыдущими вызовами?
[EDIT]
Я думаю, мой вопрос был недостаточно ясным:
У нас есть сотни клиентов, подключенных к нашему серверу.
Для каждого клиента, естественно, необходимо отправить отзыв о транзакции (OK или исключение → откат).
Мой вопрос: если я использую REQUIRED
, означает ли это только одна транзакция, а если 100-й клиент сталкивается с проблемой, первая транзакция клиента также откатится?
Ответы
Ответ 1
Использование REQUIRES_NEW
только тогда, когда метод вызывается из транзакционного контекста; Когда метод вызывается из нетранзакционного контекста, он будет вести себя точно так же, как REQUIRED
- он создаст новую транзакцию.
Это не означает, что для всех ваших клиентов будет только одна транзакция - каждый клиент будет запускаться из @Transactional
контекста, и как только обработка запроса достигнет @Transactional
, он создаст новую транзакцию.
Итак, имея это в виду, если использование REQUIRES_NEW
имеет смысл для семантики этой операции - чем бы я не беспокоился о производительности - это было бы преждевременной оптимизацией учебника - я бы предпочел подчеркнуть правильность и целостность данных и беспокоиться о производительности, как только показатели производительности были собраны, и не раньше.
При откате - использование REQUIRES_NEW
заставит начать новую транзакцию, поэтому исключение откатит эту транзакцию. Если есть и другая транзакция, которая также выполнялась - она будет или не будет откатываться в зависимости от того, является ли исключение пузырьком в стеке или перехватывается - ваш выбор, исходя из специфики операций. Кроме того, для более глубокого обсуждения транзакционных стратегий и отката я бы рекомендовал: "Стратегии транзакций: понимание подводных камней транзакций", Марк Ричардс.
Ответ 2
Если вам действительно нужно сделать это в отдельной транзакции, вам нужно использовать REQUIRES_NEW
и жить с накладными расходами. Следите за мертвыми замками.
Я предпочел бы сделать это по-другому:
- Подтвердить данные на стороне Java.
- Запустите сборку в одной транзакции.
- Если что-то пойдет не так на стороне БД → это основная ошибка БД или дизайн проверки. Отбросьте все и выбросьте критическую ошибку верхнего уровня.
- Напишите хорошие модульные тесты.