10

W moim projekcie Boot wiosennej I wprowadziły następujące metody usługa:Wiosna zagnieżdżone transakcje

@Transactional 
public boolean validateBoard(Board board) { 
    boolean result = false; 
    if (inProgress(board)) { 
     if (!canPlayWithCurrentBoard(board)) { 
      update(board, new Date(), Board.AFK); 
      throw new InvalidStateException(ErrorMessage.BOARD_TIMEOUT_REACHED); 
     } 
     if (!canSelectCards(board)) { 
      update(board, new Date(), Board.COMPLETED); 
      throw new InvalidStateException(ErrorMessage.ALL_BOARD_CARDS_ALREADY_SELECTED); 
     } 
     result = true; 
    } 
    return result; 
} 

wewnątrz tej metody używam innej metody serwisowym, który nazywa update:

@Transactional(propagation = Propagation.REQUIRES_NEW) 
public Board update(Board board, Date finishedDate, Integer status) { 
    board.setStatus(status); 
    board.setFinishedDate(finishedDate); 

    return boardRepository.save(board); 
} 

muszę popełnić zmiany w bazie danych w metodzie update niezależnie od transakcji właściciela, która jest uruchamiana w metodzie validateBoard. Teraz wszelkie zmiany są wycofywane w przypadku jakiegokolwiek wyjątku.

Nawet z @Transactional(propagation = Propagation.REQUIRES_NEW) nie działa.

Jak prawidłowo zrobić to za pomocą Spring i zezwolić na zagnieżdżone transakcje?

+4

Wygląda na to, że wywołujesz metodę w obrębie tej samej klasy, więc Spring nie może przechwycić połączenia i zastosować proxy transakcyjne (propagacja typu "REQUIRES_NEW" jest ignorowana). Powinieneś przeprowadzić migrację metody 'update' do innej fasoli Spring, –

+0

Dzięki, teraz wszystko działa zgodnie z oczekiwaniami – alexanoid

Odpowiedz

8

Dokumentacja ta obejmuje problemu - http://docs.spring.io/autorepo/docs/spring/current/spring-framework-reference/html/transaction.html

W trybie proxy (który jest domyślny), tylko metoda zewnętrznych wymaga wpadającym przez pełnomocnika są przechwytywane. Oznacza to, że samo wywołanie, w efekcie metoda w obiekcie docelowym wywołująca inną metodę obiektu docelowego, nie doprowadzi do rzeczywistej transakcji w czasie wykonywania, nawet jeśli wywoływana metoda jest oznaczona jako @Transactional. Ponadto serwer proxy musi być w pełni zainicjowany, aby zapewnić oczekiwane zachowanie, więc nie powinieneś polegać na tej funkcji w kodzie inicjującym, tj. @PostConstruct.

Jednak istnieje możliwość, aby przełączyć do trybu AspectJ

1

Twoja adnotacja dotycząca transakcji w metodzie update nie zostanie uznana przez infrastrukturę transakcji Spring, jeśli została wywołana z jakiejś metody tej samej klasy. Więcej informacji na temat działania infrastruktury transakcyjnej Spring można znaleźć pod adresem this.

0

Twój problem to sposób na połączenie z inną metodą wewnątrz tego proxy.It za siebie inwokacji. W twoim przypadku możesz go łatwo naprawić bez przenoszenia metody wewnątrz innej usługi (dlaczego potrzebujesz innej usługi tylko po to, aby przenieść jakąś metodę z jednej usługi do drugiej, aby uniknąć samo-wywoływania?), Aby wywołać drugą metoda nie bezpośrednio z obecnej klasy, ale z pojemnika sprężynowego. W takim przypadku należy wywołać drugą metodę pośrednika z transakcją, która nie jest autonowrotna.

Ta zasada przydaje się w przypadku dowolnego obiektu-proxy, gdy potrzebne jest samo-wywołanie, a nie tylko proxy transakcyjne.

@Service 
class SomeService ..... { 
    -->> @Autorired 
    -->> private ApplicationContext context; 
    -->> //or with implementing ApplicationContextAware 

    @Transactional(any propagation , it's not important in this case) 
    public boolean methodOne(SomeObject object) { 
     ....... 
     -->> here you get a proxy from context and call a method from this proxy 
     -->>context.getBean(SomeService.class). 
      methodTwo(object); 
     ...... 
    } 

    @Transactional(any propagation , it's not important in this case)public boolean 
    methodTwo(SomeObject object) { 
    ....... 
    } 
} 

kiedy robisz zadzwonić context.getBean(SomeService.class).methodTwo(object); kontenerów powraca obiekt proxy i na tej proxy można nazwać methodTwo(...) z transakcji.