2016-10-05 3 views
0

У меня есть это странное поведение с транзакциями весной.Сделка отменена предыдущей транзакцией

У меня есть два класса:

класс обслуживания, который первым вызывается doGenericServiceStuff (другим объектом, уже обладают сделки):

@Service("myService") 
public class ServiceClass { 

    public void doGenericServiceStuff(Object someBean){ 
     BusinessI business = BusinessFactory.getBusinessForObject(someBean); //Here, returns the commonBusinessClass bean 
     business.doGenericBusinessStuff(someBean); 
    } 

    /*@Transactional (readOnly=false, rollbackFor=Exception.class, propagation=Propagation.REQUIRES_NEW)*/ 
    public void firstOperation(Object o){ 
     //multiple database insert and stuff 
    } 

    /*@Transactional (readOnly=false, rollbackFor=Exception.class, propagation=Propagation.REQUIRES_NEW)*/ 
    public void secondOperation(Object o){ 
     //also multiple database insert and stuff 
    } 
} 

Тогда CommonBusinessClass, что вызывает некоторые ServiceClass' методы:

@Bean("commonBusinessClass") 
public class CommonBusinessClass implements BusinessI{ 
    @Autowired 
    @Qualifier("myService") 
    protected ServiceClass = null; 

    @Transactional(rollBackFor=Exception.class, Propagation=Propagation.MANDATORY) 
    public Object doGenericBusinessStuff(Object o){ 
     service.firstOperation(o); 
     service.secondOpertion(o); 
     //There can be stuff here in other BusinessClass 
     return o; 
    } 
} 

Отказ от ответственности: Очевидно, что я не манипулируют Objects, как это, и я не называю моей мето d doGenericStuff(). Однако ServiceClass действительно вызывает CommonBusinessClass, который, в свою очередь, вызывает ServiceClass. Может быть, это плохой дизайн, может быть, причина в том, что он не работает, но это то, что у меня есть на данный момент.

Методы в ServiceClass не являются транзакционными (поэтому комментарии), а doGenericBusinessStuff()Propagation.MANDATORY).

Новое требование заключается в том, что если secondOperation() не удался (и откаты) firstOperation(), следует совершить. Поэтому я добавил @Transactional за firstOperation() и secondOperation() (те, о которых идет речь). Я ожидал, что он будет работать нормально (исключение в secondOperation() не откатывает то, что было сделано в firstOperation()), но это не так. Однако, если я удалю @Transactional по адресу doGenericBusinessStuff(), он работает.

Это поведение нормальное, или есть что-то еще, что приходит в игру в моем реальном приложении, которое я не помещал здесь (потому что я упростил его)? Почему новая транзакция должна быть связана друг с другом каким-либо образом? Какие-нибудь идеи о том, что может случиться?

Заранее спасибо.

ответ

1

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

В вас случае у вас есть:

@Transactional(rollBackFor=Exception.class, Propagation=Propagation.MANDATORY) 
    public Object doGenericBusinessStuff(Object o){ 
     service.firstOperation(o); 
     service.secondOpertion(o); 
     //There can be stuff here in other BusinessClass 
     return o; 
    } 

Итак, если service.firstOperation(o) не работает, то вся транзакция rollbacked и это то же самое для service.secondOpertion(o). Если service.secondOpertion(o) не работает, все операции внутри doGenericBusinessStuff будут переданы в другое место.

Edit: REQUIRES_NEW может не работать в некоторых случаях, если вы используете JtaTransactionManager, например:

Примечание: Фактическая приостановка сделки не будет работать вне из коробки на всех менеджеров транзакций. Это, в частности, относится к JtaTransactionManager

От http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/transaction/annotation/Propagation.html

+0

Alright, поэтому маркировка и firstOperation как '@ Transactional' с' Propagation.REQUIRES_NEW' не сделать его независимую сделку (что не будет откатить, если 'doGenereicBusinessStuff()' делает)? – Asoub

+0

Если вы используете Propagation.REQUIRES_NEW, то Spring создаст новую независимую транзакцию. http://www.byteslounge.com/tutorials/spring-transaction-propagation-tutorial – reos

+0

Но если все ваши методы находятся в одном классе. doGenericBusinessStuff и firstOperation, то Spring transactional не создаст новую транзакцию. Весна не в состоянии справиться с этим сценарием неявно. Любая аннотация по вызываемому методу будет проигнорирована (поскольку вызов происходит на «этом», а не на прокси-сервере транзакции) Вам нужно переключиться на AspectJ для обработки такого сценария. http://stackoverflow.com/questions/28480480/propagation-requires-new-does-not-create-a-new-transaction-in-spring-with-jpa – reos

Смежные вопросы