Repeatable read - czy chroni przed nadpisywaniem zmian dokonanych przez drugą transakcję?

Repeatable read - czy chroni przed nadpisywaniem zmian dokonanych przez drugą transakcję?
P1
  • Rejestracja:ponad 14 lat
  • Ostatnio:ponad 12 lat
  • Postów:150
0

Z tego co czytałem o izolacji Repearable Read to chroni ona daną transakcję przed niepowtarzalnymi odczytami czyli że raz czytane w transakcji rekordy przy ponownym ich czytaniu w tej transakcji będą zwracały te same dane. Ale czy ten mechanizm zabezpiecza też przed nadpisywaniem wyników działania drugiej transakcji (i jeżeli tak to w jaki sposób)?
Chodzi mi o znaną sytuację gdy wątek i transakcja t1 pobiera jakieś dane, drugi wątek i transakcja t2 pobiera te same dane, obie transakcje dokonują obliczeń, druga transakcja zapisuje swoje wyniki do tego rekordu z którego pobrała dane i commituje się, pierwsza transakcja t1 kończy obliczenie i też zapisuje swój wynik do tego samego rekordu nadpisując zmianę dokonaną przez transakcje t2.

AP
  • Rejestracja:około 22 lata
  • Ostatnio:ponad 12 lat
  • Postów:3079
1

W przypadku REPETABLE READS jeżeli w pierwszej transakcji zmodyfikujesz rekord, to w drugiej transakcji nie będziesz go mógł go odczytać, dopóki pierwsza transakcja się nie zakończy. Nie będziesz mógł również w drugiej transakcji zmodyfikować rekordu, który został odczytany w pierwszej transakcji, nim ta się nie zakończy. W przypadku takim jak opisałeś czyli dwie transakcje najpierw odczytują rekordy, a następnie próbują zmodyfikować dojdzie do zakleszczenia.

P1
  • Rejestracja:ponad 14 lat
  • Ostatnio:ponad 12 lat
  • Postów:150
0

Dzięki.
Czyli samo w trybie Repeatable Reads samo przeczytanie rekordu przez transakcję t1 spowoduje że transakcja t2 nie będzie mogła go już zmodyfikować bo zostanie on zablokowany i będzie tylko do czytania dla innych transakcji?

AP
  • Rejestracja:około 22 lata
  • Ostatnio:ponad 12 lat
  • Postów:3079
0
Pierce111 napisał(a)

Dzięki.
Czyli samo w trybie Repeatable Reads samo przeczytanie rekordu przez transakcję t1 spowoduje że transakcja t2 nie będzie mogła go już zmodyfikować bo zostanie on zablokowany i będzie tylko do czytania dla innych transakcji?

Tak

KO
  • Rejestracja:ponad 13 lat
  • Ostatnio:prawie 13 lat
  • Postów:36
0
AdamPL napisał(a)

W przypadku REPETABLE READS jeżeli w pierwszej transakcji zmodyfikujesz rekord, to w drugiej transakcji nie będziesz go mógł go odczytać, dopóki pierwsza transakcja się nie zakończy. Nie będziesz mógł również w drugiej transakcji zmodyfikować rekordu, który został odczytany w pierwszej transakcji, nim ta się nie zakończy. W przypadku takim jak opisałeś czyli dwie transakcje najpierw odczytują rekordy, a następnie próbują zmodyfikować dojdzie do zakleszczenia.

Hmmmm, jak zwykle "to zależy"

Weźmy na przykład popularnego mysql-a i taką sekwencję:

Kopiuj
ses1 > set session transaction isolation level repeatable read;
Query OK, 0 rows affected (0.00 sec)

ses1 > set autocommit=0;
Query OK, 0 rows affected (0.00 sec)

ses1 > select * from test;
+----+------+
| id | val  |
+----+------+
|  1 |   10 |
+----+------+
1 row in set (0.00 sec)

[code]
ses2 > set session transaction isolation level repeatable read;
Query OK, 0 rows affected (0.00 sec)

ses2 > set autocommit=0;
Query OK, 0 rows affected (0.00 sec)

ses2 > select * from test;
+----+------+
| id | val |
+----+------+
| 1 | 10 |
+----+------+
1 row in set (0.00 sec)
[/code]

Teraz w sesji 1 robimy obliczenia i update (bez commit):
[code]
ses1 > update test set val = 5 where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
[/code]

A w sesji 2 - o dziwo - da się odczytać rekord ?
[code]
ses2 > select * from test;
+----+------+
| id | val |
+----+------+
| 1 | 10 |
+----+------+
1 row in set (0.00 sec)
[/code]

No to teraz commit w jedynce
[code]
ses1 > commit;
Query OK, 0 rows affected (0.07 sec)

ses1 > select * from test;
+----+------+
| id | val |
+----+------+
| 1 | 5 |
+----+------+
1 row in set (0.00 sec)
[/code]

I sprawdźmy w dwójce
[code]
ses2 > select * from test;
+----+------+
| id | val |
+----+------+
| 1 | 10 |
+----+------+
1 row in set (0.00 sec)
[/code]

To teraz w dwójce zapiszmy wynik nazych skomplikowanych obliczeń (bez commit)
[code]
ses2 > update test set val = 25 where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0

ses2 > select * from test;
+----+------+
| id | val |
+----+------+
| 1 | 25 |
+----+------+
1 row in set (0.00 sec)
[/code]

a teraz w jedynce odczytajmy, i zróbmy skomplikowane obliczenia
[code]
ses1 > select * from test;
+----+------+
| id | val |
+----+------+
| 1 | 5 |
+----+------+
1 row in set (0.00 sec)

ses1 > update test set val = 125 where id =1;
[/code]

jak widać - update "zawisł" w oczekiwaniu na zdjęcie blokady

to w sesji 2 robimy commit
[code]
ses2 > commit;
Query OK, 0 rows affected (0.08 sec)

ses2 > select * from test;
+----+------+
| id | val |
+----+------+
| 1 | 25 |
+----+------+
1 row in set (0.00 sec)
[/code]

i wracamy do sesji 1 - naszym oczom ukazuje się to:
[code]
Query OK, 1 row affected (2.29 sec)
Rows matched: 1 Changed: 1 Warnings: 0

ses1 > select * from test;
+----+------+
| id | val |
+----+------+
| 1 | 125 |
+----+------+
1 row in set (0.00 sec)
[/code]

Oczy nie wierzą - wracamy do 2
[code]
ses2 > select * from test;
+----+------+
| id | val |
+----+------+
| 1 | 25 |
+----+------+
1 row in set (0.00 sec)
[/code]

cuda Panie, cuda

[code]
ses2 > commit;
Query OK, 0 rows affected (0.00 sec)

ses2 > select * from test;
+----+------+
| id | val |
+----+------+
| 1 | 25 |
+----+------+
1 row in set (0.00 sec)
[/code]

i znowu 1
[code]
ses1 > commit;
Query OK, 0 rows affected (0.12 sec)

ses1 > select * from test;
+----+------+
| id | val |
+----+------+
| 1 | 125 |
+----+------+
1 row in set (0.00 sec)
[/code]

[code]
ses2 > select * from test for update;
+----+------+
| id | val |
+----+------+
| 1 | 125 |
+----+------+
1 row in set (0.00 sec)

ses2 > commit;
Query OK, 0 rows affected (0.00 sec)

ses2 > select * from test;
+----+------+
| id | val |
+----+------+
| 1 | 125 |
+----+------+
1 row in set (0.00 sec)

[/code]

Wracając do źródeł:

AdamPL napisał(a)

W przypadku REPETABLE READS jeżeli w pierwszej transakcji zmodyfikujesz rekord, to w drugiej transakcji nie będziesz go mógł go odczytać, dopóki pierwsza transakcja się nie zakończy.

Udało się odczytać

AdamPL napisał(a)

W przypadku takim jak opisałeś czyli dwie transakcje najpierw odczytują rekordy, a następnie próbują zmodyfikować dojdzie do zakleszczenia.

Nie doszło do żadnego zakleszczenia.

Polecam to samo ćwiczenie zrobić w Oraclu, potem w MSSQL następnie w PostgreeSQL ..... wnioski mogą być ciekawe ;)

edytowany 1x, ostatnio: kordirko
AP
  • Rejestracja:około 22 lata
  • Ostatnio:ponad 12 lat
  • Postów:3079
0

Cóż mogę powiedzieć. Tak kończy się praca w bazie danych o której nie ma się pojęcia. Powstaje frustracja, nerwy, wtf... a wszystko przez niewiedzę. Z tego też powodu bazą danych powinni się zajmować profesjonaliści, a nie amatorzy. Właściciele wielu firemek, powinni zainwestować w prawdziwych bazodanowców, a nie przymuszać do tego jakiś PHP-owców czy C#-owców. Później na forum 4programmers czytam jaki to "MySQL jest zjeb****", "porównajcie sobie z Oracle" itd.

@kordirko

  1. MySQL wykorzystuje domyślnie silnik InnoDB, który działa domyślnie w poziomie izolacji REPETABLE READ, nie trzeba go w ten sposób specjalnie ustawiać. W innych bazach danych domyślnym poziomem izolacji jest z kolei READ COMMITED.
  2. Polecenie SELECT czyta zawsze wartość z migawki utworzonej w momencie wejścia w transakcję, dzięki temu zwykły SELECT działa nawet wtedy gdy w innej transakcji są niezatwierdzone zmiany. To sprawia, że MySQL jest szybki i nie ma co chwila informacji o LOCK-ach.
  3. Jeżeli wchodzisz w MySQL w transakcję w której chcesz wyliczyć jakąś wartość na podstawie istniejącej już wartości oraz chcesz mieć gwarancję, że nic innego jej nie zmodyfikuje zamiast zwykłego SELECT robisz SELECT lock-ujący (FOR UPDATE lub LOCK IN SHARE MODE).
  4. Jeżeli w jednej transakcji masz zrobiony nie COMMIT-owany UPDATE, to w drugiej transakcji nie zrobisz SELECT-a lock-ującego, dojdzie do zakleszczenia.
  5. MySQL zachował się poprawnie w przedstawionym przez Ciebie przypadku. Zdania "oczom nie wierzę", "cuda panie cuda" dowodzą niestety Twojej niewiedzy i niezrozumienia tematu.

P.S. Nie odbieraj tego jako atak. Nie każdy musi się znać na wszystkim i to jest zrozumiałe. Nie atakuję Ciebie, tylko zwracam uwagę, że nie masz wystarczającej wiedzy w tym temacie.

P1
  • Rejestracja:ponad 14 lat
  • Ostatnio:ponad 12 lat
  • Postów:150
0

Dzięki za pomoc : )
Mógłbyś mi tylko wyjaśnić to zakleszczenie:

  1. Jeżeli w jednej transakcji masz zrobiony nie COMMIT-owany UPDATE, to w drugiej transakcji nie zrobisz SELECT-a lock-ującego, dojdzie do zakleszczenia.

Z tego co wiem to gdy transakcja nie może dostać jakiegoś locka to po prostu czeka na niego tak długo aż nie zostanie on zwolniony. Czyli po commitowaniu transakcji T1, transakcja T2 ruszy dalej i wykona swojego Select'a.

edytowany 1x, ostatnio: Pierce111
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)