Как вызвать пользовательский метод отката в Spring Transaction Management?

окружающая среда: Весна 3, Управление пользовательскими транзакциями, транзакции JDBC

Я просто прочитал весенние документы об использовании шаблона транзакции для управления транзакциями. это казалось слишком сложным поэтому я хочу спросить:

большинство моих транзакций связаны с JDBC, то есть я просто объявляю @Transactional на мои услуги. Но теперь ... --10-->я делаю вызов службы REST на другой сайт, который должен откатиться, если какая-либо из следующих операций JDBC не, я предоставлю код отката в этом случае.

по мере продвижения в моем методе, в моей транзакции-я хочу сохранить ссылку на вызов службы REST (необходимо откатить это действие), и при исключении я просто нужен способ myCustomRollback() под названием который может получить доступ к ранее сохраненному объекту.

почему бы просто не предоставить карту в transactionTemplate для хранения вещей и определить пользовательский метод отката на @Transactional аннотации?

вот как я думаю об этом, я не следую тому, как весна думает об этом. Может ли кто-нибудь помочь мне преодолеть разрыв между тем, что я хочу, и тем, как я делаю это наиболее эффективно весной? Мне нужно сделать это только для нескольких специальных операций.

5 ответов


вы можете использовать советы AfterThrowing (когда возникает исключение) и вызвать свой метод (myCustmRollback()) там, вы можете использовать TransactionSynchronizationManager класс, чтобы получить транзакцию thecurrent и откатить ее...

альтернативно.. вы можете использовать AroundAdvice для начала и фиксации / отката транзакции (таким образом, вы можете использовать диспетчер транзакций spring, используя TransactionSynchronizationManager класс)


всем, кто еще читает это:

я решил аналогичную проблему с весенними событиями-как предложил Ден Роман в варианте 3. Вот основная идея (сценарий вымышленный):

всякий раз, когда я выполняю внешние операции, которые необходимо откатить вместе с транзакцией, я публикую событие внутри моего @Transactional метод, используя поддержку от весны (org.springframework.context.ApplicationEventPublisher):

@Transactional
public String placeOrder(Order order) {
    String orderId = orderServiceGateway.createOrder(order);
    applicationEventPublisher.publishEvent(new OrderCreatedEvent(orderId));
    workflowService.startWorkflow(orderId);
    return orderId;
}

само событие может быть любым объектом - я создал POJO с деталями об удаленном объекте, который необходимо удалить.

затем я зарегистрировал специальный прослушиватель событий, который привязан к фазе транзакции - в моем случае к откату:

@TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK)
public void rollBackOrder(OrderCreatedEvent orderCreatedEvent) {
    String orderId = orderCreatedEvent.getOrderId();
    orderServiceGateway.deleteOrder(orderId);
}

конечно, рекомендуется поймать и зарегистрировать исключение из операции отката, чтобы не потерять исходное исключение из placeOrder() метод.

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

вот очень хорошая статья на этот механизм, включая подробную конфигурацию и подводные камни:синхронизация транзакций и весенние события приложений (DZone)

хотя мне не нравится решение 100%, потому что оно загромождает бизнес-логику публикацией событий и привязывается к spring, он определенно делает то, что я ожидаю от него, и позволяет передавать контекст из транзакционного метода в метод отката , который недоступен через традиционный блок try/catch за пределами метод (если вы не поставить свой контекст в себе исключение, что не очень приятно).


Я перечитал ваш вопрос несколько раз и не уверен, что понимаю ваш вопрос полностью. Я предполагаю, что ваш-исполнителя someCode и если это не удается, вы хотели бы выполнить myCustomRollback, который имеет некоторую информацию о someCode. Поэтому я постараюсь дать общий ответ.

Если вы хотите, чтобы spring откатил некоторый код. Это будет только откат то, что rollBackAble, как транзакции в JDBC. Предположим, у вас есть метод, который выполняет 2 звонки.

@Transactional
public void doStuff(SomeEntity entity, File file) {
   persist(entity);
   customFileService.createOnFileSystem(file);
   throw new RunTimeException();
}

Так что приведенный выше код всегда будет откат. Это отменит сохранение вашей сущности, но не создание вашего файла, так как это не управляется транзакциями Spring, если вы не предоставите пользовательскую реализацию для этого.

во-вторых, Spring предоставляет 2 способа работы с транзакциями:

  • Spring AOP: создается прокси во время который украсит ваш код транзакционными материалами. Если бы ваш класс назовите MyClass, затем Spring создаст класс myclassproxy, который будет обертывать ваш код в транзакционный код.
  • AspectJ: во время компиляции ваш .файл класса будет скорректирован, а транзакционный код будет встроен в ваш метод.

подход aspectJ кажется сложнее настроить, но не так много и проще в использовании. Поскольку все, что аннотируется с @Transactional будет встроено (сплетено) с кодом. Для весны AOP это не случай. Внутренний метод требует экземпляр весной будут игнорироваться! Таким образом, aspectJ обеспечивает более интуитивный подход.

вернемся к тому, что я думаю, ваш вопрос (кода все в 1 классе):

public void doSomeCode() {
    Object restCall = initialize();
    try {
      execute(restCall);
    } catch (CustomException e) {
      myCustomRollback(restCall; e);
    }
}

@Transactional(rollbackFor = CustomException.class)
private void execute(Object restCall) throws CustomException {
    // jdbc calls..
      restCall = callRest(restCall);
      throw new CustomException();
}

void myCustomRollback(Object restCall, CustomException e) {
   ...
}

код выше будет работать только с AspectJ! так как ваши внутренние вызовы методов, которые также кажутся частными! AOP во время выполнения не может справиться с этим.

Итак, что происходит, все (что является rollbackAble) в execute будет время отката. И в doStuff у вас есть информация об объектах, которые использовались в execute, теперь вы можете использовать в myCustomRollback для отката вашего REST материала вручную.

не уверен, правильно ли я ответил на этот вопрос, но я надеюсь, что это поможет кому-то с подобной проблемой.


управление транзакциями Spring поведение по умолчанию для автоматического отката для непроверенных исключений

Итак, для пользовательского исключения,

@Transactional(rollbackFor = CustomException.class, noRollbackFor = RuntimeException.class)
public void doSomething(...
)

транзакция будет откатываться, если есть исключение, соответствующее указанному. Если исключение не совпадает, оно передается вызывающему объекту службы или transactionrolledbackexception wrapper

Если вы используете организацию.springframework.торговая операция.PlatformTransactionManager больше управляемые исключения обработки, чем template

проверьте документацию http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/transaction.html


1 решение заключается в реализации собственного транзакционного менеджера путем расширения one

2 решение заключается в использовании класса TransactionSynchronizationManager

3 решение использовать @TransactionalEventListener в случае, если у вас есть Весна 4