#java #spring #spring-data
Вопрос:
С Spring по умолчанию используются транзакции Propogation.REQUIRED
, но мне это кажется довольно странным выбором. Если мы игнорируем существование транзакций, то это очень нормальный шаблон, чтобы поймать исключение и реализовать запасной вариант. Например, в очень простой форме:
public void doSomethingFirst() {} public void doSomethingElse() {} public void doSomethingWithFallback() { this.doSomething(); try { this.doSomethingElse(); } catch (Exception e) { this.fallback(); } }
Однако Propagation.REQUIRED
это нарушает:
public void doSomethingFirst() { } @Transactional(propagation = Propagation.REQUIRED) public void doSomethingElse() { } @Transactional(propagation = Propagation.REQUIRED) public void doSomethingWithFallback() { this.doSomethingFirst(); try { this.doSomethingElse(); } catch (Exception e) { this.fallback(); } }
Теперь, если doSomethingElse
произойдет сбой, он отметит транзакцию только как откат. Даже несмотря на то, что у нас есть отличный запасной вариант, вся транзакция будет откатана, и мы ничего не сможем сделать, чтобы остановить это.
«Исправление» для этого заключается в использовании NESTED
вместо REQUIRED
(по крайней мере, в doSomethingElse
):
public void doSomethingFirst() { } @Transactional(propagation = Propagation.NESTED) public void doSomethingElse() { } @Transactional(propagation = Propagation.NESTED) public void doSomethingWithFallback() { this.doSomethingFirst(); try { this.doSomethingElse(); } catch (Exception e) { this.fallback(); } }
Теперь мы используем точки сохранения, и в случае doSomethingElse
сбоя это приведет только к откату doSomethingElse
.
Мне кажется NESTED
, что это поведение, которого мы почти всегда хотим, и я изо всех сил пытаюсь придумать какой-либо вариант использования, который REQUIRED
был бы предпочтительнее. REQUIRED
запрещает вызывающему абоненту восстанавливаться после ошибок, что обычно является плохой идеей.
Но, учитывая, что REQUIRED
это значение по умолчанию, и оно NESTED
почти никогда не используется, наверняка должна быть какая-то причина, по которой мы должны использовать REQUIRED
его снова NESTED
.
В каких случаях мы должны REQUIRED
предпочесть NESTED
?
Комментарии:
1. То
@Transactional
, что наdoSomethingElse
то, бесполезно. Не каждая база данных поддерживает точки сохранения, в то время как все они поддерживаютREQUIRED
. Кроме того, он также используется по умолчанию для транзакций для EJBs, и Spring соответствует этому с момента своего создания. Кроме того, то, что вы считаете базовой практикой (т. Е. резервным вариантом), не является таким уж базовым или распространенным. Когда вы пишете что-то, что либо терпит неудачу, либо преуспевает, я не хочу делать что-то еще. Если бы вы действительно хотели, вы могли бы сделать это в новой транзакции вместо того, чтобы также использовать точки сохранения.2.
@Transactional
ВключениеdoSomethingElse
определенно не бесполезно.doSomethingElse
может выполнять несколько операций, требующих транзакции, и может использоваться в нескольких контекстах. И в любой достаточно сложной системе вы обязательно будете использовать резервные варианты, где это уместно. Новая транзакция имеет совершенно другие характеристики, хотя это вовсе не замена вложенной3. Несмотря на это, меня втягивают в детали, но в этом нет смысла. Вопрос в том , когда
REQUIRED
следует предпочестьNESTED
, и в своем комментарии вы обратились к этому только с поддержкой БД. Итак, давайте перефразируем это немного по-другому: если ваша БД поддерживает точки сохранения, зачем использовать REQUIRED вместо ВЛОЖЕННЫХ?4. Ваш вопрос касается значения по умолчанию, на который был дан ответ, потому что он соответствует поведению EJB по умолчанию и что не все базы данных поддерживают это. Кроме того, то, что вы считаете обычным делом, не так распространено, как вы думаете. Наконец, большинству проектов требуется операция «все или ничего», а не полная или частичная операция, которую вы получили бы с ВЛОЖЕННЫМИ.