JPA Repository, Spring i transakcja w transakcji

0

Mam dwie klasy:

PodanieTradycyjneService.java

@Service
@Scope
@Transactional
public class PodanieTradycyjne {
    
    @Autowired
    PodanieTradycyjneRepository podanieTradycyjneRepository;

    public void rejestruj(PodanieDTO podanieDTO) {

        Set<ConstraintViolation<PodanieDTO>> cvSet = validator.validate(podanieDTO, Rejestracja.class);
        if (!cvSet.isEmpty()) {
            throw new ConstraintViolationException(cvSet); //tu podanie elektroniczne nie spelnia wymogow walidacyjnych i rzuca blad
        }
        
        podanieTradycyjneService.rejestruj(podanieDTO); // Tutaj metoda wola repository i robi save
    }
}

PodanieElektroniczneService.java

@Service
@Scope
@Transactional
public class PodanieElektroniczneService {
    @Autowired
    PodanieTradycyjneService podanieTradycyjneService;
    @Autowired
    PodanieTradycyjneRepo podanieTradycyjneRepo;

    public void rejestrujPodanieElektroniczne() {
        podanieTradycyjneService.rejestruj();
        podanieTradycyjneRepo.save()// tutaj zapisuje dodatkowa encje, ktorej nie zapisuje przy podaniu tradycyjnym
    }
}

ERROR:

org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly

Domyślam się, że chodzi o to, że jest transakcja w transakcji. I podczas rzucania wyjątku PodanieElektroniczneService chce zrobić rollbacka. Ale nie wiem jak to sensownie rozwiązać.

Jakieś pomysły?

0

Problem polega na tym że jeśli wewnątrz transakcji poleci wyjątek to automatycznie ustawia sie ona w tryb rollback only, nawet jeśli złapiesz ten wyjątek. Logika jest taka że skoro był wyjątek to coś poszlo nie tak i trzeba wycofać zmiany. Ale ja nie bardzo rozumiem jaki efekt chcesz w takim razie uzyskać w tej sytuacji. Można określić w @Transactional(rollbackFor=ExceptionOne.class, noRollbackFor=ExceptionTwo.class) ale nie wiem czy o to ci chodzi.
A tak poza tym to używaj interfejsów a nie klas bo pewnie 2 dni straciłeś na to, żeby ustawić w Springu robienie proxy dla klas bez interfejsów za pomocą cgliba żeby ci to transactional w ogóle działalo ;)

Poza tym nie bardzo rozumiem czemu masz transactional na poziomie klasy która niczego do bazy nie zapisuje. Trochę dziwny to pomysł i potencjalny problem wydajnościowy.

0

Po pierwsze po co ci transakcja w transakcji ??
po dwa, pokaż stacktrace, cały

0

Transakcja w transakcji to nie takie nic niezwykłego. Serwis A w metodzie transakcyjnej korzysta z metody transakcyjnej z serwisu B. Rzecz w tym, że metoda w B przed rozpoczęciem swojej transakcji sprawdza (za pośrednictwem mechanizmów kontenera) czy istnieje aktywna transakcja. Jeżeli istnieje to podpina się do niej. Jak w B poleci wyjątek to transakcja zostanie oznaczona jako nieudana i całość się sypie.

Rozwiązaniem jest użycie Requires_new na metodzie z B. Wtedy wywołanie tej metody rozpocznie nową transakcje niezależnie czy istnieje jakaś aktywna. Wyjątek w tej transakcji nie zaburza pracy transakcji zewnętrznej...

ale...

Jeżeli w B poleci wyjątek i ta transakcja zostanie wycofana, a w A korzystasz z tego co produkowane jest w B to masz niespójne dane i poważny problem.

0

@Koziołek Dokładnie jest tak jak napisałeś. Po napisaniu posta wpadłem na to by dać propadation REQUIRED_NEW, ale potem okazało się właśnie, że może być taki problem o którym napisałeś.

Dlatego rozwiązałem to tak, że

Serwis B rzucał wyjątek do Serwisu A tam przechwytywałem wyjątek ConstraintViolationException następnie w Klasie widoku BeanABC łapałem wyjątek:
org.springframework.transaction.TransactionSystemException

Wszystko przy domyślnym propagation REQUIRED.

0

Źle... Stwórz własny wyjątek i niech B wali nim do A. W A obsługa i wypchnięcie do BeanABC. Łapanie TransactionSystemException bo to "błąd biznesowy" jest słabe z kilku względów...

  1. Traktujesz go jak błąd biznesowy, a tym samym uzależniasz się od frameworku ORAZ wiążesz logikę biznesową z mechanizmami ją realizującymi.
  2. Spring potrafi obsłużyć taki błąd po swojemu, a twoja ingerencja może spowodować jakieś dziwne zachowania.
  3. W widoku łapanie... naprawdę...

1 użytkowników online, w tym zalogowanych: 0, gości: 1