Различия в поведении распространения REQUIRES_NEW и NESTED в транзакциях Spring - PullRequest
0 голосов
/ 21 октября 2018

Предисловие

Прежде всего:

Не является дубликатом Различия между require_new и вложенным распространением в транзакциях Spring - Я прочитал его, но не нашел ответа на мой вопрос

Вопрос:

После прочтения упомянутой мной темы я понял, чтоосновное различие между уровнями распространения в количестве физических транзакций:
2 дБ транзакций - для REQUIRES_NEW для внешнего и для внутреннего метода
1 дБ транзакций - для NESTED для внешнего и внутреннегометод.Это не будет работать, если базовая база данных не поддерживает точки сохранения

Но похоже, логика будет той же самой с моей точки зрения, если смотреть.

Как понять, какой уровень использовать на практике?Есть ли варианты использования, чтобы понять это?Полезные примеры поведенческих различий?

PS
Я полагаю, что есть некоторые видимости для других различий транзакций, потому что различное время фиксации транзакции.

PS2

Также я предполагаю, что есть разница в производительности:

@Transactional
public void outer(){
    for(int i=0;i<100500;i++){
        inner();
    }   
}

@Transactional
public void inner(){
   //some logic
}

В этом случае NESTED будет лучше из-за 1 длинной физической транзакции вместо 100500 + 1

Ответы [ 3 ]

0 голосов
/ 02 ноября 2018

Как в вашем примере, если бы inner() имел:

@Transactional(propagation=Propagation.REQUIRES_NEW)
public void inner(){
   //some logic
}

Тогда, если бы он вызвал исключение из второго вызова в цикле outer(), изменения от первого вызова имели быуже зафиксировано - его REQUIRES_NEW.

Если бы inner() имел:

@Transactional(propagation=Propagation.NESTED)
public void inner(){
   //some logic
}

Тогда изменения от первого вызова будут откатываться - потому что в перехватчике нет блокаouter().


Точка, в которой уровень распространения на inner() действительно начинает иметь значение, заключается в том, будет ли цикл outer() обрабатывать исключения в inner():

@Transactional
public void outer() {
    for (int i = 0; i < 100500; i++) {
        try {
            inner();
        } catch (Exception ex) {
            // Report and continue
        }
    }
    // Something else that could fail
}

Очевидно, что REQUIRES_NEW и NESTED сохранят изменения только от успешных вызовов inner().Ключевое отличие заключается в том, что с NESTED есть возможность выбросить все это, если в outer() последует сбой.

Как вы говорите, другой фактор - это масштабируемость - некоторые базы данныхвозможно, не оценят размер родительской транзакции с NESTED распространением.


Также, возможно, стоит сказать - хотя я подозреваю, что в этом примере мы стремились к ясности.Прямой вызов this.inner() обходится консультантом транзакций Spring.Необходимо разрешить вводить «рекомендованный компонент», чтобы аннотация @Transactional могла выполнять свою магию до и после вызова - например, nextAutowiredBean.inner().

0 голосов
/ 04 ноября 2018

Если ваша внутренняя логика не зависит от внешней логики, тогда используйте Requ_new, если не используете nested.

Например, ваш внешний метод может обрабатывать задание, содержащее большое количество записей, и вызывать внутренний метод, который сохраняет статус задания (ход выполнения, предупреждения и ошибки проверки).Вы хотели бы, чтобы транзакция внутренних методов была независимой, и ее изменения в БД были сохранены немедленно, чтобы какая-то другая часть системы могла отображать ход выполнения.Если внешний метод встречает исключение, его транзакция будет откатываться, но транзакции внутреннего метода не будут.

Вы хотели бы использовать вложенные или зависимые транзакции, когда необходимо, чтобы внешние и внутренние изменения либо сохранялись, либооба будут свернуты вместе.Например, вам нужно создать нового пользователя (используя «внешний» сервис) и сохранить его адрес (используя «внутренний» сервис).Если ваши требования состоят в том, что у пользователя должен быть адрес, то при сохранении пользователя или адреса не удастся откатить оба изменения.

0 голосов
/ 22 октября 2018

Наблюдаются большие различия:

в случае вложенности:

  • Если откат внешней транзакции выполняется, откат вложенной транзакции также выполняется.
  • visibility : если БД выполняет MVCC, что является довольно распространенным,
    • вложенный tra видит предыдущие изменения внешнего tra.
    • изменения вложенного traбудет виден зафиксированным и видимым для других tras после фиксации внешнего.
  • производительность: помните, что рабочий набор внешних транзакций расширяется внутренними транзакциями.Таким образом, больше блокировок, больше памяти preimage для MVCC, более длинная запись в журнале повторов.

В случае require_new:

  • Если внешняя транзакция откатывается, изменения внутреннего tra не будут откатываться в случае отката внешнего tra.
  • видимость : в случае MVCC, что довольно часто,
    • внутренний тра не увидит изменений, сделанных еще не совершенным внешним тра.
    • изменения вложенного tra будут рассматриваться как зафиксированные и видимые для других tras сразу после фиксации этого внутреннего tra, даже до фиксации внешнего tra.Меньше блокировок, но из-за того, что многие совершают больше внешних операций, больше записей в повторной блокировке.

В случае производительности , если другие факторы не важны, вы можете найти разрыв даже между размером транзакции и номером транзакции.imO нет общего ответа на вопрос, если вложенность быстрее, чем require_new.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...