Jedna transakcja shared a wielowątkowość

0

Cześć mam pytanko, nie wiem jak do tego podejść ale.

screenshot-20240204115107.png

Zdjęcie jak ma to wyglądać 😄 Mamy 2 tabelki z danymi (A i B)
Potrzebuje zrobić "snapshot" danych, dane A pozwolą mi stworzyć dane B (prawa strona) oraz muszą być zapisane do innej tabelki A (przekopiowane z A lewo do A prawo).
C tabelka również ma być przekopiowana.

Chciałbym to zrobić równolegle tylko problem pojawia się podczas współdzielenia transakcji.
Bo nie może istnieć sytuacja taka, że proces A się wykona (czyli zapisze do A i B) a C nie wykona się bo będzie jakiś error.
Jak wyczytałem z użyciem metody Transactional on tworzy sobie za każdym razem nową transkacje, jak próbowałem dawać parametr Mandatory (w pod metodzie) to dostawałem błąd że transakcja nie istnieje co by się zgadzało z opisem że nie jest dzielona.

Czy ktoś mógłby jakoś doradzić jak/czym albo jak sobie z tym poradzić ?

(Próbowałem to z użyciem CompletableFuture)

Dzięki za każdą poradę 😉

0

Brzmi to jak javowsko-springowy YX problem

@Transacinal to pole minowe
A pachnąca tu między wierszami rozproszona transakcja to nie mniejszy problem.

0

Chciałbym to zrobić równolegle tylko problem pojawia się podczas współdzielenia transakcji.

Dlaczego równolegle? Co zyskujesz kosztem złożoności rozwiązania?

Poprawnie byłoby zbudować logikę, które obsługuje wykonanie Twojego workflow i mieć mechanizm, który jest w stanie wyszukać instancje workflow, które padły i wznowić ich wykonanie.
Zamiast

activity1.execute();
activity2.execute();

coś w stylu

MyBusinessProcess process = MyBusinessProcess(activity1,activity2);
process.execute();

Gdzie ten MyBusinessProcess zamyka maszyną stanową/workflowem, który jest w stanie "kontynuować wykonanie procesu zgodnie z logiką, której potrzebujesz" (trzeba to sobie oprogramować, można wykorzystać istniejące frameworki).

Kolejna sprawa, to piszesz, że równolegle... ale co z przeplotami wykonania? Piszesz o abstrakcyjnych tabelach A,B,C, ale gdyby C nie było w jakiś sposób związane z przetwarzaniem A,B to chyba problemu by nie było? Czy robi Ci różnicę kolejność w jakiej zadania rozpoczną pracę i w jakiej zakończą pracę i jaki będzie stan (zawartość) tabel A,B,C w określonym punkcie czasu?

np. możesz mieć takie przeploty (| - momenty rozpoczęcia/zakończenie zadania, - - wykonanie zadania)

Task #1: |------------------------|
Task #2: |------------------------|

Task #1: |------------------------|
Task #2:    |---------------------|

Task #1: |------------------------|
Task #2:    |-------------------|
...

Przeplot#1 - Task#1 i #2 zaczynają i kończą się dokładnie w tym samym czasie (mało prawdopodobne ale mocno zależne od tego "jak i gdzie mierzymy czas")
Przeplot#2 - Task#1 zaczyna się wcześniej niż 2, ale kończą w tym samym momencie
Przeplot#3 - Task#2 zaczyna się później niż task#1, ale kończy wcześniej niż Task#1
...

0
yarel napisał(a):

Chciałbym to zrobić równolegle tylko problem pojawia się podczas współdzielenia transakcji.

Dlaczego równolegle? Co zyskujesz kosztem złożoności rozwiązania?

Poprawnie byłoby zbudować logikę, które obsługuje wykonanie Twojego workflow i mieć mechanizm, który jest w stanie wyszukać instancje workflow, które padły i wznowić ich wykonanie.
Zamiast

activity1.execute();
activity2.execute();

coś w stylu

MyBusinessProcess process = MyBusinessProcess(activity1,activity2);
process.execute();

Gdzie ten MyBusinessProcess zamyka maszyną stanową/workflowem, który jest w stanie "kontynuować wykonanie procesu zgodnie z logiką, której potrzebujesz" (trzeba to sobie oprogramować, można wykorzystać istniejące frameworki).

Kolejna sprawa, to piszesz, że równolegle... ale co z przeplotami wykonania? Piszesz o abstrakcyjnych tabelach A,B,C, ale gdyby C nie było w jakiś sposób związane z przetwarzaniem A,B to chyba problemu by nie było? Czy robi Ci różnicę kolejność w jakiej zadania rozpoczną pracę i w jakiej zakończą pracę i jaki będzie stan (zawartość) tabel A,B,C w określonym punkcie czasu?

np. możesz mieć takie przeploty (| - momenty rozpoczęcia/zakończenie zadania, - - wykonanie zadania)

Task #1: |------------------------|
Task #2: |------------------------|

Task #1: |------------------------|
Task #2:    |---------------------|

Task #1: |------------------------|
Task #2:    |-------------------|
...

Przeplot#1 - Task#1 i #2 zaczynają i kończą się dokładnie w tym samym czasie (mało prawdopodobne ale mocno zależne od tego "jak i gdzie mierzymy czas")
Przeplot#2 - Task#1 zaczyna się wcześniej niż 2, ale kończą w tym samym momencie
Przeplot#3 - Task#2 zaczyna się później niż task#1, ale kończy wcześniej niż Task#1
...

"Dlaczego równolegle? Co zyskujesz kosztem złożoności rozwiązania? "

Tylko po to żeby przyspieszyć proces.

"(trzeba to sobie oprogramować, można wykorzystać istniejące frameworki). "

Masz jakieś fajne na myśli ? Mi z tego co kojarzę jest Spring Batch tylko nie wiem czy to nie jest armata do muchy.

"> Kolejna sprawa, to piszesz, że równolegle... ale co z przeplotami wykonania? Piszesz o abstrakcyjnych tabelach A,B,C, ale gdyby C nie było w jakiś sposób związane z przetwarzaniem A,B to chyba problemu by nie było? Czy robi Ci różnicę kolejność w jakiej zadania rozpoczną pracę i w jakiej zakończą pracę i jaki będzie stan (zawartość) tabel A,B,C w określonym punkcie czasu?"

C jako tako nie jest powiązane z A i B w sensie jeśli chodzi o kalkulacje czy coś natomiast nie może być takiej sytuacji że A i B się przekalkuluje a C wyskoczy gdzieś error i nie przekopiuje.
C również może się zacząć później i skończyć wcześniej nie ma to wpływu.

Przez to myślałem nad jakąś transakcją ale może dobrym pomysłem by było "ala proces" to ogarnąć.

2

Dla mnie też brzmi jak XY problem.

W świecie Springowym zazwyczaj:

  • @Transactional na metodzie
  • @Async na metodzie
  • @Version nad polem encji

i zazwyczaj działa xD

1
ArturoS159 napisał(a):

...

"Dlaczego równolegle? Co zyskujesz kosztem złożoności rozwiązania? "

Tylko po to żeby przyspieszyć proces.

Czy sekwencyjnie jest zbyt wolno? O ile będzie szybciej ?

"(trzeba to sobie oprogramować, można wykorzystać istniejące frameworki). "

Masz jakieś fajne na myśli ? Mi z tego co kojarzę jest Spring Batch tylko nie wiem czy to nie jest armata do muchy.

Szukaj pod hasłami: Java FSM, Spring FSM, z bardziej złożonych rozwiązań: Flowable, Activiti, Camunda. Ale to musisz mieć dobry powód do takiej złożoności.

0

Podstawowe pytanie - czy to jest w obrębie jednej bazy danych czy więcej niż jednej.

  1. Jeśli to w obrębie jednej bazy danych, a baza ma taką opcję to zcedowałbym kopiowanie do bazy danych - i transakcje trzymał właśnie tam. W ostatecznym rozrachunku takie zabawy na zbiorach w bazie danych są najprostsze właśnie na bazie danych.
  2. W przypadku gdy kopiujesz z bazy do bazy i nie masz aż tak wielu danych to wystarczy użyć executora:
@Service
public class SynchronizationService {
  private final SourceRepository source;
  private final TargetRepository target;
  private final ConcurrentTaskExecutor executor;

  // konstruktor

  @Transactional
  public void synchronize() {
    // zadziała, jeśli storeTableA i storeTableC będą też oznaczone @Transactional
    CompletableFuture.allOf(
      executor.submit(() -> source.getTableA()).andThenAccept(list -> target.storeTableA(list)),
      executor.submit(() -> source.getTableC()).andThenAccept(list -> target.storeTableC(list))
    ).join();
  }
}

  1. W końcu - jeśli masz dużo danych to dobrze użyć batch processingu.
0
wartek01 napisał(a):

... są najprostsze właśnie na bazie danych.

Dlaczego sposób podania tematu mi się kojarzy z Excellem ?

ArturoS159 napisał(a):

Potrzebuje zrobić "snapshot" danych,

ArturoS159 napisał(a):

"Dlaczego równolegle? Co zyskujesz kosztem złożoności rozwiązania? "

Tylko po to żeby przyspieszyć proces.

No tak, snapshoty z bazy są znanym sposobem polepszenie wydajności
Integralności zresztą też ;)

1

@wartek01 nie żebym się czepiał, ale może czegoś nie rozumiem z magii springowej (tzn. na pewno nie rozumiem :-)), ale jeśli chodzi Twój przykład, to tam masz 3xTransactional:

  • Transactional-1 na wątku głównym (z którego wołasz synchronize())
  • Transactional2-3 na wątkach executora

Każdy taki transactional działa w ramach kontekstu transakcyjnego, który w springu jest utrzymywany per wątek (i domyślnie, w ramach tego samego wątku jest propagowany na kolejne metody oznaczone Transactional). Masz więc 3 transakcje (jedna na wątku głównym) i te 2 z executora. Jak storetTableA przejdzie, a storeTableC się wywali, to chyba nie będzie stanu o jaki autorowi posta chodzi.

0

Masz dwa niezależne procesy do ogarnięcia.

  • wyliczanie B na podstawie A oraz zapisanie kopii A z których wyliczono B.
  • kopiowanie C.

To wszystko chcesz uruchomić w ramach jednej transakcji, a raczej chcesz to uruchomić na raz.

Użyj Spring Batch, to jest bardzo proste i lekkie rozwiązanie. w którym musisz ogarnąć jedynie konfigurację zadań. Cała reszta „zrobi się sama”.

Job 1 – kopiowanie danych w C
Job 2 – trzystopniowy, czyli pobranie A, i dwa równoległe kroki wyliczanie B, zapisywanie A`.

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