Как откатить внешнюю транзакцию в случае неудачной внутренней транзакции, но внутренняя транзакция должна сохранить данные Spring - PullRequest
1 голос
/ 15 мая 2019

Попытка предотвратить откат внутренних транзакций. если ответ внутренних транзакций не SUCCESS, то внешние транзакции должны откатываться, но внутренняя транзакция должна сохранять данные.

@Transactional(rollbackFor=Exception.class, propagation=Propagation.REQUIRES_NEW)
private void test1(Account account) throws Exception {
    DOA.save(account);
    status = test2(account);
    if(status!='SUCCESS'){
        throw new Exception("api call failed");
    }
}
@Transactional(propagation=Propagation.MANDATORY)
private void test2(Account account) {
    response //API Call
    DOA.save(response);
    return response.status;
}

Ответы [ 2 ]

2 голосов
/ 15 мая 2019

Сконфигурируйте внутренний транзакционный метод как Propagation.REQUIRES_NEW, чтобы он всегда фиксировал (т.е. сохранял данные), когда метод завершает работу, независимо от того, выполняется откат внешнего транзакционного метода или нет.

Кроме того, убедитесь, что внешний метод выполняетне собственный вызов внутреннего метода, так как @Transactional в этом случае не работает (см. раздел Видимость метода и раздел @Transactional в документах ).

Они должны находиться в разных bean-компонентах, которые внешний методвызывает bean-компонент внутреннего метода:

@Service
public class Service1 {

    @Autowired
    private Service2 service2;

    @Transactional(rollbackFor=Exception.class)
    public void test1(Account account) throws Exception {
        DOA.save(account);
        status = service2.test2(account);
        if(status!='SUCCESS'){
            throw new Exception("Api call failed");
        }
    }
}

@Service
public class Service2{

    @Transactional(propagation=Propagation.REQUIRES_NEW)
    public void test2(Account account) {
        response // API Call
        DOA.save(response);
        return response.status;
    }
}
0 голосов
/ 15 мая 2019

@Transactional игнорируется для вашего метода Test2, и вызов является частью одной транзакции.

две вещи, которые следует учитывать здесь, как говорит Spring doc, -

Видимость метода и @ Transactional

При использовании прокси вы должны применить@ Транзакционная аннотация только для методов с публичной видимостью.Если вы аннотируете защищенные, частные или видимые пакетами методы с помощью аннотации @Transactional, ошибка не возникает, но аннотированный метод не отображает настроенные параметры транзакции.Рассмотрите возможность использования AspectJ (см. Ниже), если вам нужно аннотировать закрытые методы.

Режим прокси

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

Если вы хотите сохранить данные для внутреннего метода, вы можете выбрать запуск новой транзакции для метода Test2, чтобы он не влиял на существующую транзакцию, запущенную Test1.

Но она не запустит новую Транзакцию в вашем случае, даже если вы сделаете Test2 публичной, потому что она вызывается из того же класса.

Solution -

  1. Вы можете использовать режим aspectj в настройках транзакции, чтобы начать новую транзакцию для внутреннего метода.
  2. Поместите свой внутренний метод в состав другого компонента и отметьте Propagation.REQUIRES_NEW
  3. , чтобы запустить транзакцию вручную Программно начать новую транзакцию
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...