Transakcje
Commit i rollback
Transakcje to bezpłatna lekcja Java Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Java Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Java Academy zawiera 4 lekcji w sumie.
Czym jest transakcja
Transakcja grupuje kilka operacji SQL w jedną jednostkę wykonywaną w całości albo wcale.
Albo każda instrukcja kończy się powodzeniem i zmiany zostają trwale zapisane (commit), albo coś się nie powiedzie i wszystkie zmiany zostaną wycofane (rollback). Dzięki temu baza danych zachowuje spójność.
ACID w minutę
Transakcje zapewniają gwarancje ACID:
- Atomowość — wszystko albo nic.
- Spójność — przenosi bazę danych z jednego prawidłowego stanu do innego.
- Izolacja — równoczesne transakcje nie powodują wzajemnego uszkodzenia danych.
- Trwałość — po zatwierdzeniu zmiany przetrwają awarię.
Tryb automatycznego zatwierdzania
Domyślnie połączenia JDBC działają w trybie auto-commit: każda instrukcja stanowi osobną transakcję i jest natychmiast zatwierdzana.
Sprawdza się to w przypadku pojedynczych instrukcji, ale nie działa, gdy kilka operacji zapisu musi zakończyć się powodzeniem jako całość. Aby samodzielnie sterować transakcjami, należy wyłączyć auto-commit.
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class Main {
public static void main(String[] args) {
String url = "jdbc:postgresql://localhost:5432/bank";
try (Connection conn = DriverManager.getConnection(url, "app", "secret")) {
System.out.println("Default auto-commit: " + conn.getAutoCommit());
conn.setAutoCommit(false);
System.out.println("Now manual: " + conn.getAutoCommit());
} catch (SQLException e) {
System.out.println(e.getMessage());
}
}
}Commit i rollback
Przy wyłączonym auto-commit samodzielnie określa się granice transakcji:
conn.commit()trwale zapisuje wszystkie oczekujące zmiany.conn.rollback()je odrzuca.
Klasycznym przykładem jest przelew pieniędzy: obciążenie jednego konta i uznanie drugiego. Obie operacje muszą się udać albo żadna z nich.
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class Main {
public static void main(String[] args) {
String url = "jdbc:postgresql://localhost:5432/bank";
String debit = "UPDATE account SET balance = balance - ? WHERE id = ?";
String credit = "UPDATE account SET balance = balance + ? WHERE id = ?";
try (Connection conn = DriverManager.getConnection(url, "app", "secret")) {
conn.setAutoCommit(false);
try (PreparedStatement d = conn.prepareStatement(debit);
PreparedStatement c = conn.prepareStatement(credit)) {
d.setInt(1, 100); d.setInt(2, 1); d.executeUpdate();
c.setInt(1, 100); c.setInt(2, 2); c.executeUpdate();
conn.commit();
System.out.println("Transfer committed");
} catch (SQLException ex) {
conn.rollback();
System.out.println("Rolled back: " + ex.getMessage());
}
} catch (SQLException e) {
System.out.println(e.getMessage());
}
}
}Schemat wycofania w razie błędu
Struktura do zapamiętania:
- Należy wyłączyć auto-commit.
- Pracę należy wykonać wewnątrz wewnętrznego
try. - Po pomyślnym zakończeniu należy wywołać
commit(). - W bloku
catchnależy wywołaćrollback(), a następnie ponownie zgłosić błąd lub go zalogować.
Bez rollbacku awaria mogłaby pozostawić bazę danych częściowo zaktualizowaną.
Symulowanie atomowości
Oto idea wykonania wszystkiego albo niczego, przedstawiona w zwykłym kodzie Java, aby można było uruchomić go samodzielnie. Stosujemy dwie aktualizacje do migawki; jeśli którakolwiek się nie powiedzie, przywracamy migawkę.
public class Main {
public static void main(String[] args) {
int[] balances = {500, 300};
int[] backup = balances.clone();
try {
balances[0] -= 200;
if (balances[0] < 0) throw new IllegalStateException("insufficient funds");
balances[1] += 200;
System.out.println("Commit: " + balances[0] + ", " + balances[1]);
} catch (RuntimeException e) {
balances = backup;
System.out.println("Rollback: " + balances[0] + ", " + balances[1]);
}
}
}Punkty zapisu
Punkt zapisu to znacznik wewnątrz transakcji. Można wycofać zmiany do tego punktu bez odrzucania całej transakcji.
Savepoint sp = conn.setSavepoint()conn.rollback(sp)wycofuje tylko zmiany wykonane po tym punkcie.
Jest to przydatne przy częściowym odzyskiwaniu danych w długich transakcjach.
Poziomy izolacji
Izolacja określa, co jedna transakcja widzi z niezatwierdzonych zmian drugiej. JDBC definiuje poziomy za pomocą conn.setTransactionIsolation(...):
TRANSACTION_READ_COMMITTED— często używany poziom domyślny.TRANSACTION_REPEATABLE_READTRANSACTION_SERIALIZABLE— najsilniejszy, ale najwolniejszy.
Wyższy poziom izolacji zapobiega anomaliom, ale ogranicza współbieżność.
Anomalie odczytu
Niższe poziomy izolacji mogą umożliwiać:
- Brudny odczyt — odczytanie niezatwierdzonej zmiany innej transakcji.
- Odczyt niepowtarzalny — wiersz zmienia się między dwoma odczytami.
- Odczyt fantomowy — pojawiają się nowe wiersze pasujące do wcześniejszego zapytania.
Należy wybrać najniższy poziom, który nadal zapobiega anomaliom niedopuszczalnym dla danej logiki.
Przywracanie auto-commit
Jeśli połączenie pobrano z puli, przed jego zwróceniem należy przywrócić jego pierwotny stan.
Po ręcznie zarządzanej transakcji należy ponownie ustawić conn.setAutoCommit(true) (lub przywrócić wartość odczytaną podczas pobierania), aby kolejny użytkownik nie został zaskoczony tymi ustawieniami.
Krótkie transakcje
Transakcja utrzymuje blokady do momentu zatwierdzenia lub wycofania. Długie transakcje blokują inne operacje i zwiększają ryzyko zakleszczeń.
- Nie należy wykonywać wolnych wywołań sieciowych ani oczekiwać na działania użytkownika wewnątrz otwartej transakcji.
- Najpierw należy zebrać dane, a następnie szybko otworzyć transakcję, wykonać zapis i ją zatwierdzić.
Krótkie transakcje o jasno określonym zakresie znacznie lepiej się skalują.
Szybkie sprawdzenie
Jaki jest skutek wywołania connection.rollback()?
Podsumowanie
Transakcje zapewniają bezpieczeństwo dzięki zasadzie „wszystko albo nic”:
- Należy wyłączyć auto-commit za pomocą
setAutoCommit(false). - Po powodzeniu wywołać
commit(), a w razie błędurollback(). - Używać punktów zapisu do częściowego wycofywania zmian.
- Dostosowywać poziomy izolacji, aby zachować równowagę między poprawnością a współbieżnością.
- Przed zwróceniem połączenia do puli przywrócić auto-commit.
Często zadawane pytania
Czy lekcja „Transakcje” jest bezpłatna?
Tak — pełny tekst „Transakcje” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Java Academy, przejdź na CoddyKit PRO. Kurs Java Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Transakcje”?
Commit i rollback Ćwiczysz Java Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Java Academy?
Nie wymagamy żadnego doświadczenia. Java Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.
Ile czasu zajmuje lekcja „Transakcje”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Java Academy?
Tak. Każda lekcja Java Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.