MySQL
TABELA BLOKADY MySQL
Szukaj…
Składnia
LOCK TABLES nazwa_tabeli [CZYTAJ | PISAĆ]; // Blokuj tabelę
ODBLOKUJ TABELE; // Odblokuj tabele
Uwagi
Blokowanie służy do rozwiązywania problemów związanych z współbieżnością. Blokowanie jest wymagane tylko podczas przeprowadzania transakcji, która najpierw odczytuje wartość z bazy danych, a następnie zapisuje tę wartość w bazie danych. Blokady nigdy nie są wymagane do samodzielnych operacji wstawiania, aktualizacji lub usuwania.
Dostępne są dwa rodzaje zamków
ODCZYTAJ BLOKADĘ - gdy użytkownik czyta tylko ze stołu.
BLOKADA ZAPISU - gdy użytkownik zarówno czyta, jak i pisze do tabeli.
Gdy użytkownik trzyma WRITE LOCK
na stole, żaden inny użytkownik nie może czytać ani zapisywać na tym stole. Gdy użytkownik trzyma READ LOCK
na stole, inni użytkownicy mogą również czytać lub blokować READ LOCK
, ale żaden użytkownik nie może pisać ani WRITE LOCK
na tym stole.
Jeśli domyślnym silnikiem pamięci jest InnoDB, MySQL automatycznie stosuje blokowanie na poziomie wiersza, dzięki czemu wiele transakcji może jednocześnie używać tej samej tabeli do odczytu i zapisu, bez konieczności wzajemnego oczekiwania.
We wszystkich silnikach pamięci innych niż InnoDB, MySQL stosuje blokowanie tabel.
Aby uzyskać więcej informacji na temat blokady stołu Zobacz tutaj
Zamki MySQL
Blokady tabel mogą być ważnym narzędziem dla ENGINE=MyISAM
, ale rzadko są przydatne dla ENGINE=InnoDB
. Jeśli masz ochotę korzystać z blokad tabel w InnoDB, powinieneś przemyśleć sposób pracy z transakcjami.
MySQL umożliwia sesjom klienckim jawne uzyskiwanie blokad tabel w celu współpracy z innymi sesjami w celu uzyskania dostępu do tabel lub w celu zapobiegania modyfikowaniu tabel przez inne sesje w okresach, gdy sesja wymaga do nich wyłącznego dostępu. Sesja może uzyskać lub zwolnić blokady tylko dla siebie. Jedna sesja nie może uzyskać blokad dla innej sesji ani zwolnić blokad przechowywanych przez inną sesję.
Blokady mogą być używane do emulacji transakcji lub zwiększenia prędkości podczas aktualizowania tabel. Wyjaśniono to bardziej szczegółowo w dalszej części tego rozdziału.
Polecenie: LOCK TABLES table_name READ|WRITE;
możesz przypisać tylko typ blokady do pojedynczej tabeli;
Przykład (READ LOCK):
LOCK TABLES table_name READ;
Przykład (BLOKADA ZAPISU):
LOCK TABLES table_name WRITE;
Aby zobaczyć, czy zastosowano blokadę, użyj następującego polecenia
SHOW OPEN TABLES;
Aby opróżnić / usunąć wszystkie blokady, użyj następującego polecenia:
UNLOCK TABLES;
PRZYKŁAD:
LOCK TABLES products WRITE:
INSERT INTO products(id,product_name) SELECT id,old_product_name FROM old_products;
UNLOCK TABLES;
W powyższym przykładzie żadne połączenie zewnętrzne nie może zapisać żadnych danych do tabeli produktów, dopóki nie odblokuje produktu tabeli
PRZYKŁAD:
LOCK TABLES products READ:
INSERT INTO products(id,product_name) SELECT id,old_product_name FROM old_products;
UNLOCK TABLES;
W powyższym przykładzie żadne połączenie zewnętrzne nie może odczytać żadnych danych z tabeli produktów do momentu odblokowania produktu tabeli
Blokowanie na poziomie rzędu
Jeśli tabele używają InnoDB, MySQL automatycznie stosuje blokowanie na poziomie wiersza, dzięki czemu wiele transakcji może jednocześnie używać tej samej tabeli do odczytu i zapisu, bez konieczności wzajemnego oczekiwania.
Jeśli dwie transakcje próbują zmodyfikować ten sam wiersz i obie wykorzystują blokowanie na poziomie wiersza, jedna z transakcji czeka na zakończenie drugiej.
Blokowanie na poziomie wiersza można również uzyskać za pomocą SELECT ... FOR UPDATE
dla każdego wiersza, który ma zostać zmodyfikowany.
Rozważ dwa połączenia, aby szczegółowo wyjaśnić blokowanie na poziomie wiersza
Połączenie 1
START TRANSACTION;
SELECT ledgerAmount FROM accDetails WHERE id = 1 FOR UPDATE;
W połączeniu 1 blokada poziomu wiersza uzyskana przez SELECT ... FOR UPDATE
.
Połączenie 2
UPDATE accDetails SET ledgerAmount = ledgerAmount + 500 WHERE id=1;
Gdy ktoś spróbuje zaktualizować ten sam wiersz w połączeniu 2, będzie czekać na zakończenie transakcji przez połączenie 1 lub wyświetli się komunikat o błędzie zgodnie z ustawieniem innodb_lock_wait_timeout
, który domyślnie innodb_lock_wait_timeout
50 sekund.
Error Code: 1205. Lock wait timeout exceeded; try restarting transaction
Aby wyświetlić szczegółowe informacje na temat tej blokady, uruchom SHOW ENGINE INNODB STATUS
---TRANSACTION 1973004, ACTIVE 7 sec updating
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 360, 1 row lock(s)
MySQL thread id 4, OS thread handle 0x7f996beac700, query id 30 localhost root update
UPDATE accDetails SET ledgerAmount = ledgerAmount + 500 WHERE id=1
------- TRX HAS BEEN WAITING 7 SEC FOR THIS LOCK TO BE GRANTED:
Połączenie 2
UPDATE accDetails SET ledgerAmount = ledgerAmount + 250 WHERE id=2;
1 row(s) affected
Ale podczas aktualizacji jakiś inny wiersz w połączeniu 2 zostanie wykonany bez żadnego błędu.
Połączenie 1
UPDATE accDetails SET ledgerAmount = ledgerAmount + 750 WHERE id=1;
COMMIT;
1 row(s) affected
Teraz blokada wiersza jest zwolniona, ponieważ transakcja jest zatwierdzana w Połączeniu 1.
Połączenie 2
UPDATE accDetails SET ledgerAmount = ledgerAmount + 500 WHERE id=1;
1 row(s) affected
Aktualizacja jest wykonywana bez żadnego błędu w Połączeniu 2 po zwolnieniu blokady wiersza 1 przez zakończenie transakcji.