Czy ktoś może wyjaśnić, jakie są parametry izolacji i propagacji w @Transactional
adnotacji na przykładzie z prawdziwego świata?
Zasadniczo kiedy i dlaczego powinienem zmienić ich wartości domyślne.
Czy ktoś może wyjaśnić, jakie są parametry izolacji i propagacji w @Transactional
adnotacji na przykładzie z prawdziwego świata?
Zasadniczo kiedy i dlaczego powinienem zmienić ich wartości domyślne.
Dobre pytanie, choć nie jest trywialne.
Określa relacje między transakcjami. Typowe opcje:
Required
: Kod zawsze będzie działał w transakcji. Tworzy nową transakcję lub wykorzystuje ją ponownie, jeśli jest dostępna.Requires_new
: Kod zawsze będzie działał w nowej transakcji. Zawiesza bieżącą transakcję, jeśli taka istnieje.Definiuje umowę danych między transakcjami.
Read Uncommitted
: Pozwala na brudne odczyty.Read Committed
: Nie zezwala na brudne odczyty.Repeatable Read
: Jeśli wiersz zostanie odczytany dwukrotnie w tej samej transakcji, wynik zawsze będzie taki sam.Serializable
: Wykonuje wszystkie transakcje po kolei.Różne poziomy mają różne parametry wydajnościowe w aplikacji wielowątkowej. Myślę, że jeśli zrozumiesz dirty reads
pojęcie, będziesz mógł wybrać dobrą opcję.
Przykład wystąpienia brudnego odczytu:
thread 1 thread 2
| |
write(x) |
| |
| read(x)
| |
rollback |
v v
value (x) is now dirty (incorrect)
Tak więc rozsądnym ustawieniem domyślnym (jeśli można tak twierdzić) może być Read Committed
tylko odczytanie wartości, które zostały już zatwierdzone przez inne uruchomione transakcje, w połączeniu z poziomem propagacji wynoszącym Required
. Następnie możesz pracować stamtąd, jeśli Twoja aplikacja ma inne potrzeby.
Praktyczny przykład tego, gdzie nowa transakcja będzie zawsze tworzona przy wchodzeniu do provideService
rutyny i zakończona przy wychodzeniu:
public class FooService {
private Repository repo1;
private Repository repo2;
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void provideService() {
repo1.retrieveFoo();
repo2.retrieveFoo();
}
}
Gdybyśmy skorzystali zamiast tego Required
, transakcja pozostałaby otwarta, gdyby transakcja była już otwarta podczas wprowadzania procedury. Należy również zauważyć, że wynik a rollback
może być inny, ponieważ kilka egzekucji może brać udział w tej samej transakcji.
Możemy łatwo zweryfikować zachowanie za pomocą testu i zobaczyć, jak wyniki różnią się w zależności od poziomów propagacji:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:/fooService.xml")
public class FooServiceTests {
private @Autowired TransactionManager transactionManager;
private @Autowired FooService fooService;
@Test
public void testProvideService() {
TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
fooService.provideService();
transactionManager.rollback(status);
// assert repository values are unchanged ...
}
Z poziomem propagacji wynoszącym
Requires new
: spodziewalibyśmy się, że NIEfooService.provideService()
został wycofany, ponieważ stworzył własną sub-transakcję.
Required
: spodziewalibyśmy się, że wszystko zostało wycofane, a sklep z podkładami pozostał niezmieniony.
sessionFactory.getCurrentTransaction()
został dodany, nie trzebaHibernateTemplate
już uruchamiać zarządzania transakcjami. Usunąłem go :)PROPAGATION_REQUIRED = 0 ; Jeśli DataSourceTransactionObject T1 jest już uruchomiony dla metody M1. Jeśli dla innej metody M2 wymagany jest obiekt transakcji, nie jest tworzony nowy obiekt transakcji. Dla obiektu M2 używany jest ten sam obiekt T1
PROPAGATION_MANDATORY = 2 ; Metoda musi działać w ramach transakcji. Jeśli żadna istniejąca transakcja nie jest w toku, zostanie zgłoszony wyjątek
PROPAGATION_REQUIRES_NEW = 3 ; Jeśli DataSourceTransactionObject T1 jest już uruchomiony dla metody M1 i jest w toku (wykonywanie metody M1). Jeśli inna metoda M2 zacznie działać, wówczas T1 zostanie zawieszony na czas metody M2 z nowym DataSourceTransactionObject T2 dla M2.M2 uruchomionym w ramach własnego kontekstu transakcji
PROPAGATION_NOT_SUPPORTED = 4 ; Jeśli DataSourceTransactionObject T1 jest już uruchomiony dla metody M1. Jeśli inna metoda M2 jest uruchomiona jednocześnie. Następnie M2 nie powinien działać w kontekście transakcji. T1 jest zawieszony do czasu ukończenia M2.
PROPAGATION_NEVER = 5 ; Żadna z metod nie działa w kontekście transakcji.
Poziom izolacji: Chodzi o to, jak duży wpływ na transakcję mogą mieć działania innych równoczesnych transakcji. Zapewnia spójność, pozostawiając dane w wielu tabelach w spójnym stanie. Polega na blokowaniu wierszy i / lub tabel w bazie danych.
Problem z wieloma transakcjami
Scenariusz 1. Jeżeli transakcja T1 odczytuje dane z tabeli A1, która została zapisana przez inną równoległą transakcję T2, jeżeli w drodze wycofywania T2 dane otrzymane przez T1 są nieprawidłowe, np. Dane a = 2 są danymi oryginalnymi. Jeśli T1 odczytał a = 1, który został napisany przez T2. Jeśli wycofanie T2, a = 1 zostanie cofnięte do a = 2 w DB, ale teraz T1 ma a = 1, ale w tabeli DB jest zmienione na a = 2.
Scenariusz 2. Jeśli transakcja T1 odczytuje dane z tabeli A1. Jeśli inna transakcja równoległa (T2) aktualizuje dane w tabeli A1. Następnie dane odczytane przez T1 różnią się od tabeli A1. Ponieważ T2 zaktualizowało dane w tabeli A1. przeczytaj a = 1 i T2 zaktualizowane a = 2. Następnie a! = b.
Scenariusz 3. Jeżeli transakcja T1 odczytuje dane z tabeli A1 z określoną liczbą wierszy. Jeśli inna jednoczesna transakcja (T2) wstawi więcej wierszy w tabeli A1. Liczba wierszy odczytanych przez T1 różni się od wierszy w tabeli A1
Scenariusz 1 nosi nazwę Brudne odczyty.
Scenariusz 2 nazywa się odczytami niepowtarzalnymi.
Scenariusz 3 nosi nazwę Odczyty fantomowe.
Zatem poziom izolacji to zakres, w którym można zapobiec Scenariuszowi 1, Scenariuszowi 2, Scenariuszowi 3 . Całkowity poziom izolacji można uzyskać, stosując blokowanie. Zapobiega to jednoczesnemu odczytywaniu i zapisywaniu tych samych danych, ale wpływa na wydajność. Poziom izolacji zależy od aplikacji wymaganej izolacji.
ISOLATION_READ_UNCOMMITTED : Pozwala odczytać zmiany, które nie zostały jeszcze zatwierdzone. Dotyczy scenariusza 1, scenariusza 2, scenariusza 3
ISOLATION_READ_COMMITTED : Pozwala na odczyty z jednoczesnych transakcji, które zostały zatwierdzone. Może to dotyczyć scenariusza 2 i scenariusza 3. Ponieważ inne transakcje mogą aktualizować dane.
ISOLATION_REPEATABLE_READ : Wiele odczytów tego samego pola da te same wyniki, dopóki nie zostanie zmienione samodzielnie. Może to mieć wpływ na Scenariusz 3. Ponieważ inne transakcje mogą wstawiać dane
ISOLATION_SERIALIZABLE : Scenariusz 1, Scenariusz 2, Scenariusz 3 nigdy się nie zdarza. Jest to całkowita izolacja. Obejmuje pełne blokowanie. Ma zdolność wykonywania z powodu blokowania.
Możesz przetestować za pomocą
Możesz debugować i zobaczyć wynik z różnymi wartościami izolacji i propagacji.
źródło
Wystarczające wyjaśnienie każdego parametru podano w innych odpowiedziach; Jakkolwiek prosiłeś o przykład z prawdziwego świata, oto ten, który wyjaśnia cel różnych opcji propagacji :
Załóżmy, że jesteś odpowiedzialny za wdrożenie usługi rejestracji, w której użytkownik otrzymuje wiadomość e-mail z potwierdzeniem. Pojawiają się dwa obiekty usługowe, jeden do rejestracji użytkownika i jeden do wysyłania wiadomości e-mail, który ten drugi nazywany jest wewnątrz pierwszego. Na przykład coś takiego:Być może zauważyłeś, że druga usługa ma typ propagacji REQUIRES_NEW, a ponadto istnieje prawdopodobieństwo, że zgłasza wyjątek (wyłączenie serwera SMTP, nieprawidłowa wiadomość e-mail lub inne przyczyny). Prawdopodobnie nie chcesz, aby cały proces był wycofywany, np. usuwanie informacji o użytkowniku z bazy danych lub innych rzeczy; dlatego wywołujesz drugą usługę w oddzielnej transakcji.
Wracając do naszego przykładu, tym razem martwisz się bezpieczeństwem bazy danych, więc zdefiniuj swoje klasy DAO w ten sposób:Oznacza to, że za każdym razem, gdy tworzony jest obiekt DAO, a tym samym potencjalny dostęp do db, musimy zapewnić, że połączenie zostało wykonane z jednej z naszych usług, co oznacza, że transakcja na żywo powinna istnieć; w przeciwnym razie wystąpi wyjątek, dlatego propagacja jest typu OBOWIĄZKOWA .
źródło
Poziom izolacji określa, w jaki sposób zmiany wprowadzone w niektórych repozytoriach danych przez jedną transakcję wpływają na inne jednoczesne transakcje, a także w jaki sposób i kiedy te zmienione dane stają się dostępne dla innych transakcji. Kiedy definiujemy transakcję za pomocą frameworka Spring, jesteśmy również w stanie skonfigurować, na jakim poziomie izolacji ta sama transakcja zostanie wykonana.
Poziom izolacji READ_UNCOMMITTED stwierdza, że transakcja może odczytać dane, które są nadal niezatwierdzone przez inne transakcje.
Poziom izolacji READ_COMMITTED stwierdza, że transakcja nie może odczytać danych, które nie zostały jeszcze zatwierdzone przez inne transakcje.
Poziom izolacji REPEATABLE_READ stwierdza, że jeśli transakcja odczytuje jeden rekord z bazy danych wiele razy, wynik wszystkich tych operacji odczytu musi być zawsze taki sam.
SERIALIZABLE poziom izolacji jest najbardziej restrykcyjnym ze wszystkich poziomów izolacji. Transakcje są wykonywane z blokowaniem na wszystkich poziomach (blokowanie odczytu, zakresu i zapisu), dzięki czemu wydają się być wykonywane w sposób szeregowy.
Propagacja to zdolność do decydowania o tym, w jaki sposób metody biznesowe powinny być zawarte w logicznych lub fizycznych transakcjach.
Zachowanie WYMAGANE na wiosnę oznacza, że ta sama transakcja zostanie użyta, jeśli istnieje już otwarta transakcja w bieżącym kontekście wykonania metody komponentu bean.
Zachowanie REQUIRES_NEW oznacza, że kontener zawsze tworzy nową fizyczną transakcję.
Zachowanie NESTED powoduje, że zagnieżdżone transakcje sprężynowe używają tej samej transakcji fizycznej, ale ustawia punkty zapisu między zagnieżdżonymi wywołaniami, aby transakcje wewnętrzne mogły również być wycofywane niezależnie od transakcji zewnętrznych.
Zachowanie OBOWIĄZKOWE stwierdza, że istniejąca otwarta transakcja musi już istnieć. Jeśli nie, wyjątek zostanie zgłoszony przez kontener.
Zachowanie NIGDY nie stanowi, że istniejąca otwarta transakcja nie może już istnieć. Jeśli istnieje transakcja, kontener zgłosi wyjątek.
Zachowanie NOT_SUPPORTED zostanie wykonane poza zakresem jakiejkolwiek transakcji. Jeśli otwarta transakcja już istnieje, zostanie ona wstrzymana.
Zachowanie WSPIERA zostanie wykonane w zakresie transakcji, jeśli otwarta transakcja już istnieje. Jeśli nie ma już otwartej transakcji, metoda zostanie wykonana mimo wszystko w sposób nietransakcyjny.
źródło
Transakcja reprezentuje jednostkę pracy z bazą danych.
W
TransactionDefinition
interfejsie wiosennym , który definiuje właściwości transakcji zgodne ze sprężyną.@Transactional
adnotacja opisuje atrybuty transakcji w metodzie lub klasie.Postrzeganie blokady: poziom izolacji określa czas trwania blokady.
Czytaj postrzeganie: występują następujące 3 rodzaje głównych problemów:
UPDATES
z innego tx.INSERTS
i / lubDELETES
z innego txPoziomy izolacji z różnymi rodzajami odczytów:
dla przykładów
źródło
Prawie nigdy nie chcesz używać,
Read Uncommited
ponieważ nie jest tak naprawdęACID
zgodny.Read Commmited
jest dobrym domyślnym miejscem początkowym.Repeatable Read
jest prawdopodobnie potrzebny tylko w scenariuszach raportowania, zestawienia lub agregacji. Zauważ, że wiele baz danych, w tym postgres, w rzeczywistości nie obsługuje powtarzalnego odczytu, musiszSerializable
zamiast tego użyć .Serializable
jest przydatny w przypadku rzeczy, o których wiesz, że muszą się zdarzyć całkowicie niezależnie od wszystkiego innego; pomyśl o tym jaksynchronized
w Javie. Serializowalność idzie w parze zREQUIRES_NEW
propagacją.Używam
REQUIRES
do wszystkich funkcji, które uruchamiają zapytania UPDATE lub DELETE, a także funkcji poziomu usług. W przypadku funkcji poziomu DAO, które uruchamiają tylko SELECT, używam,SUPPORTS
która będzie uczestniczyć w TX, jeśli jest już uruchomiona (tj. Wywołana z funkcji serwisowej).źródło
Izolacja transakcji i propagacja transakcji, chociaż są powiązane, ale wyraźnie są to dwie bardzo różne koncepcje. W obu przypadkach wartości domyślne są dostosowywane w komponencie granicy klienta za pomocą Deklaratywnego zarządzania transakcjami lub Programowego zarządzania transakcjami . Szczegóły dotyczące każdego poziomu izolacji i atrybutów propagacji można znaleźć w odnośnikach poniżej.
Izolacja transakcji
W przypadku danych dwóch lub więcej działających transakcji / połączeń z bazą danych, jak i kiedy zmiany dokonywane przez zapytania w jednej transakcji wpływają / są widoczne dla zapytań w innej transakcji. Odnosiło się to również do tego, jakiego rodzaju blokowanie rekordów bazy danych zostanie wykorzystane do odizolowania zmian w tej transakcji od innych transakcji i odwrotnie. Zazwyczaj jest to realizowane przez bazę danych / zasób uczestniczący w transakcji.
.
Propagacja transakcji
W aplikacji korporacyjnej dla dowolnego żądania / przetwarzania istnieje wiele komponentów, które są zaangażowane w wykonanie zadania. Niektóre z tych komponentów oznaczają granice (początek / koniec) transakcji, która będzie używana w odpowiednim komponencie i jego podskładnikach. W przypadku tej granicy transakcyjnej komponentów Propogacja transakcji określa, czy dany komponent będzie uczestniczył w transakcji, a co się stanie, jeśli wywołujący komponent już ma lub nie ma już utworzonej / uruchomionej transakcji. Jest to to samo, co atrybuty transakcji Java EE. Zazwyczaj jest to realizowane przez menedżera transakcji / połączeń klienta.
Odniesienie:
Zarządzanie transakcjami wiosennymi
Wiki Transaction Isolation (systemy baz danych)
Oracle na poziomach izolacji transakcji
Atrybuty transakcji Java EE (propagacja)
Propagacja transakcji Spring Framework
źródło
Mam biegać
outerMethod
,method_1
amethod_2
w trybie innym propagacji.Poniżej przedstawiono dane wyjściowe dla innego trybu propagacji.
Metoda zewnętrzna
Metoda_1
Metoda 2
źródło
Możemy dodać do tego:
źródło
Możesz użyć w ten sposób:
Możesz użyć tej rzeczy również:
źródło