2008-09-24 15 views
25

Mam aplikację - bardziej przypominającą narzędzie - która znajduje się w kącie i okresowo aktualizuje dwie różne bazy danych.Jaki jest najlepszy sposób wykonywania transakcji rozproszonych w wielu bazach danych przy użyciu Spring i Hibernate

Jest to niewielka samodzielna aplikacja, która została zbudowana w kontekście aplikacji wiosennej. Kontekst ma dwie skonfigurowane fabryki sesji hibernacji, z kolei za pomocą źródeł danych DBCP Commons skonfigurowanych na wiosnę.

Obecnie nie ma zarządzania transakcjami, ale chciałbym dodać kilka. Aktualizacja jednej bazy danych zależy od udanej aktualizacji drugiej.

Aplikacja nie znajduje się w kontenerze Java EE - jest bootstrapowana przez statyczną klasę launchera wywoływaną ze skryptu powłoki. Klasa launcher tworzy kontekst aplikacji, a następnie wywołuje metodę na jednym z jej komponentów.

Jaki jest "najlepszy" sposób na umieszczenie transakcji w aktualizacjach bazy danych?

Zostawię dla ciebie definicję "najlepsze", ale myślę, że powinna to być funkcja "łatwa do skonfigurowania", "łatwa do skonfigurowania", "niedroga" i "łatwa do spakowania i redystrybucji" . Oczywiście FOSS byłby dobry.

Odpowiedz

26

Najlepszy sposób na dystrybucję transakcji na więcej niż jedna baza danych to: Nie.

Niektóre osoby wskażą Ci XA, ale XA (lub Dwuetapowe zatwierdzenie) jest kłamstwem (lub marketese).

Wyobraź sobie: Po pierwszym etapie poinformował menedżera XA, że może wysłać ostateczne zatwierdzenie, połączenie sieciowe z jedną z baz danych nie powiedzie się. Co teraz? Koniec czasu? To zostawiłoby drugą bazę danych uszkodzoną. Cofanie zmian? Dwa problemy: nie można wycofać zatwierdzenia i skąd wiadomo, co stało się z drugą bazą danych? Może połączenie sieciowe nie powiodło się po pomyślnym zatwierdzeniu danych i utracono tylko komunikat "sukces"?

Najlepszym sposobem jest skopiowanie danych w jednym miejscu. Użyj schematu, który pozwala przerwać kopiowanie i kontynuować ją w dowolnym momencie (na przykład zignoruj ​​dane, które już posiadasz lub zamów wybrane przez ID i żądaj tylko rekordów> MAX (ID) twojej kopii). Chroń to za pomocą transakcji. Nie stanowi to problemu, ponieważ czytasz dane tylko ze źródła, więc gdy transakcja nie powiedzie się z jakiegokolwiek powodu, możesz zignorować źródłową bazę danych. Dlatego jest to zwykła stara transakcja z jednym źródłem.

Po skopiowaniu danych przetwórz je lokalnie.

+5

Transakcje rozproszone muszą zawierać wszystkie 4 właściwości ACID. Jaki masz problem? Opisany scenariusz nie może się zdarzyć, ponieważ menedżerowie komunikują się ze sobą i zatwierdzają tylko wtedy, gdy wszystkie uczestniczące węzły wymieniły "GO". – Falcon

+6

@Falcon: A co się stanie, jeśli sieć zawiedzie pomiędzy PREPARE a COMMIT? A może jeden z serwerów umiera? "nie może się zdarzyć" nie może się zdarzyć w rzeczywistości. –

+2

Nie, nie są instruowane, aby wycofać, ponieważ w tym scenariuszu niektóre węzły już zostały zatwierdzone. Co się stanie, gdy uszkodzony węzeł stanie się dostępny, koordynator transakcji każe mu ponownie zatwierdzić. Ponieważ węzeł odpowiedział pozytywnie w fazie "przygotowania", musi mieć możliwość "zatwierdzenia", nawet jeśli wróci z awarii. –

6

Skonfiguruj menedżera transakcji w swoim kontekście. Dokumenty wiosny mają przykłady i są bardzo proste. Wtedy, gdy chcemy wykonać transakcję:

try { 
    TransactionTemplate tt = new TransactionTemplate(txManager); 

    tt.execute(new TransactionCallbackWithoutResult(){ 
    protected void doInTransactionWithoutResult(
      TransactionStatus status) { 
     updateDb1(); 
     updateDb2(); 
    } 
} catch (TransactionException ex) { 
    // handle 
} 

Więcej przykładów i informacji może wyglądać w ten sposób: XA transactions using Spring

+3

Ten przykład tak naprawdę nie odpowiada na pytanie, a nawet odpowiada błędnie: OP wspomniał, że miał dwie skonfigurowane fabryki sesji Hibernate, które wymagałyby dwóch oddzielnych menedżerów transakcji. Przykład w odpowiedzi używa tylko jednego menedżera transakcji, który nie jest bliżej określony. Użycie pojedynczego menedżera transakcji Hibernate nigdy nie wycofałoby jednego z dwóch baz danych o błędach. Używanie na przykład 'ChainedTransactionManager' (jak zauważył @Pani Dhakshnamurthy) może pomóc, ale nie jest to wspomniane w tej odpowiedzi. – Chriki

5

Kiedy mówisz „dwóch różnych baz danych”, masz na myśli różne serwery baz danych, lub dwa różne schematy na tym samym serwerze DB?

Jeśli to pierwsze, to jeśli chcesz mieć pełną transakcyjność, potrzebujesz interfejsu API transakcji XA, który zapewnia pełne zatwierdzanie dwufazowe. Ale co ważniejsze, potrzebujesz także koordynatora/monitora transakcji, który zarządza propagacją transakcji pomiędzy różnymi systemami baz danych. Jest to część specyfikacji JavaEE, a także dość rzadka jej część. Sam koordynator TX jest złożonym oprogramowaniem. Twoje oprogramowanie aplikacyjne (przez Spring, jeśli sobie tego życzysz) rozmawia z koordynatorem.

Jeśli jednak masz na myśli dwie bazy danych na tym samym serwerze DB, to transakcje JDBC w wanilii powinny działać dobrze, po prostu wykonuj operacje na obu bazach danych w ramach jednej transakcji.

3

W tym przypadku potrzebny jest monitor transakcji (serwer obsługujący protokół XA) i upewnij się, że twoje bazy danych obsługują także XA. Większość (wszystkich?) Serwerów J2EE ma wbudowany Monitor Transakcji. Jeśli Twój kod działa nie na serwerze J2EE, jest kilka samodzielnych alternatyw - Atomicos, Bitronix itp.

Powiązane problemy