2010-03-29 9 views
7

Mam dziwny problem (przynajmniej dla mnie :)) z blokadą MySQL.WYBIERZ MYSQL DO AKTUALIZACJI - dziwny numer

Mam tabeli:

create table `test` ( 
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=latin1 

Z tych danych:

+ ---- +
| id |
+ ---- +
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 10 |
| 11 |
| 12 |
+ ---- +

Teraz mam 2 klientów z tych poleceń wykonywanych na początku:

zestaw AUTOCOMMIT = 0;
zestaw szeregowalny poziom izolacji transakcji sesji;
Rozpocznij;

Teraz najciekawsza część. Pierwszy klient wykonuje to zapytanie: (tworzy intencję wstawienia wiersza o identyfikatorze równym 9)

SELECT * z testu gdzie id = 9 FOR UPDATE;
zbiór pusty (0,00 s)

Następnie drugi klient ma takie same:

SELECT * z testów gdzie id = 9, dla aktualizacji;
Empty set (0.00 sec)

Moje pytanie brzmi: Dlaczego drugi klient nie blokuje? Wyłączna blokada luki powinna zostać ustawiona przy pierwszym zapytaniu, ponieważ FOR UPDATE zostały użyte, a drugi klient powinien blokować.

Jeśli się mylę, czy ktoś mógłby mi powiedzieć, jak zrobić to poprawnie?

Wersja MySQL używam to: 5.1.37-1ubuntu5.1

+0

Nie blokuje, ponieważ udało się zablokować ** zero ** wierszy. – Pacerier

Odpowiedz

3

Ponieważ w tym czasie, to na pewno zwróci (pusty) wynik - nie ma blokady, aby ustawić dla rekordu z id = 9, ponieważ nie istnieje i dlatego nie może być aktualizowany - nie sądzę, że można polegać na ustawieniu innodb blokad odczytu w takim przypadku. Powinien jednak ustawić blokadę zapisu na id = 9.

Jeśli w późniejszym czasie jedna z transakcji zaktualizuje tabelę i dotknie tych samych danych, co inna transakcja - aktualizacja prawdopodobnie zablokuje jedną z transakcji, a następnie zakończy się niepowodzeniem, jeśli druga transakcja dokona tych danych.Jest zupełnie normalne, że transakcje zawodzą w takich scenariuszach - pozostawiając ci obsługę - co zwykle jest kwestią ponownej transakcji.

Jeśli był zapis o id = 9, prawdopodobnie zobaczysz blok 2. select aż do zakończenia pierwszej transakcji, ponieważ teraz jest rekord, który należy odczytać zablokowany w przypadku, gdy pierwsza transakcja zdecyduje się na aktualizację w tym wierszu.

+1

Tak, jeśli istnieje rekord o numerze id = 9, 2. wybierz bloki. Jak więc "zarezerwować" identyfikator 9? Mam ten problem, ponieważ przechowuje się pewien związek między parami obiektów i chcę tylko jeden wiersz dla danej pary obiektów. –

+0

Trudno powiedzieć dokładnie, co próbujesz zrobić. Czy jedna z twoich transakcji utworzy id = 9? w takim przypadku druga transakcja zakończy się niepowodzeniem/zostanie wycofana. – nos

+0

Próbuję zaimplementować coś takiego w Javie: if (! RowExists (9)) { createRowWithId (9); } else { return "Błąd"; } I otrzymuję zduplikowane identyfikatory ... –