Wpis z mikrobloga

Jak zaimplementować zagnieżdżone (nested) transakcje w JDBC? Scenariusz:
begin
begin
update...
commit
rollback
Dane powinny zostać nienaruszone po rollbacku.

Próbowałem z savepointami, tj. begin -> setSavepoint, rollback -> rollback(savepoint), commit -> connection.commit(), ale podejrzewam, że commit usuwa wszystkie poprzednio ustawione savepointy, bo wyrzuca mi wyjątek "Savepoint is invalid" tylko przy zewnętrznym rollbacku.

#programowanie #java
  • 12
@size: Goły JDBC. Jedyne rozwiązanie, które jak na razie zaimplementowałem, to po prostu nie commitować, gdy jestem w wewnętrznej transakcji. A sprawdzam to używając getAutoCommit, tj. autocommit == true <=> transakcja zewnętrzna. Nie ma jakiegoś standardowego rozwiązania w JDBC?
@patste: A begin wywołujesz tylko raz? Bo mi się wydaje, że powinieneś dla każdej transakcji (wewnętrznej też).

Kiedyś (dużo przed jdbc 3.0) robiłem to ręcznie tak:
Tworzyłęm jakiś wrapper na connection i w nim z każdym beginem zwiększałem jakiś wewnętrzny licznik, a z każdym commitem - zmniejszałem. Prawdziwy commit wykonywałem tylko gdy licznik==0. Oczywiście przy wystąpieniu rollback niezależnie od poziomu zagnieżdżenia zerowałem licznik i wykonywałem rollback od razu. W ten sposób
P.S. getAutoCommit to nie musi być sygnał, że jesteś lub nie jesteś w transakcji. W JDBC w ogóle chyba nie ma możliwości sprawdzenia tego (choć mogę się mylić).
W sumie jeśli się zastanowić, to savePointy też Ci chyba niewiele dadzą jeśli i tak chcesz wycofać albo zacommitować całą transakcję. Nie wiem, czy coś w JDBC się zmieniło, może jakiś bardziej oblatany Mirek mnie poprawi, ale chyba ten mój wrapperek to będzie to, czego potrzebujesz.
@moriturius: Mam funkcje w najniższej warstwie, które potrzebują transakcji. Są także funkcje w warstwie wyższej, które używają tych z warstwy niższej i też potrzebują transakcji. Po za tym napisałem testy, które po zakończeniu robią rollbacka i nie naruszają danych.
@patste: masz dwie warstwy, zależne od siebie i obie wiedzą o bazie danych pod spodem. Zdecydowanie potrzebny refaktor.
A te testy to integracyjne? nawet jeśli tak, to robisz je źle bo aplikacja nie pracuje w środowisku zbliżonym do produkcyjnego. Powinieneś stworzyć embeddowaną bazę dla testu i sobie w niej działać.