Poniżej znajduje się prosty przykład z FOR UPDATE blokada intencji . Zamek na poziomie rzędu z silnikiem INNODB. Przykład pokazuje cztery wiersze dla następnych dostępnych sekwencji, które nie ucierpią z powodu dobrze znanej anomalii przerw INNODB (przypadek, w którym przerwy występują po nieudanym użyciu AUTO_INCREMENT).
Schemat:
-- drop table if exists sequences;
create table sequences
( id int auto_increment primary key,
sectionType varchar(200) not null,
nextSequence int not null,
unique key(sectionType)
) ENGINE=InnoDB;
-- truncate table sequences;
insert sequences (sectionType,nextSequence) values
('Chassis',1),('Engine Block',1),('Brakes',1),('Carburetor',1);
Przykładowy kod:
START TRANSACTION; -- Line1
SELECT nextSequence into @mine_to_use from sequences where sectionType='Carburetor' FOR UPDATE; -- Line2
select @mine_to_use; -- Line3
UPDATE sequences set nextSequence=nextSequence+1 where sectionType='Carburetor'; -- Line4
COMMIT; -- Line5
Idealnie nie masz Line3
lub w ogóle bloaty kod, który opóźniłby innych klientów na Lock Wait. Oznacza to, że pobierz następną sekwencję do użycia, wykonaj aktualizację (część zwiększająca się) i COMMIT
, jak najszybciej .
Powyższe w procedurze składowanej:
DROP PROCEDURE if exists getNextSequence;
DELIMITER $$
CREATE PROCEDURE getNextSequence(p_sectionType varchar(200),OUT p_YoursToUse int)
BEGIN
-- for flexibility, return the sequence number as both an OUT parameter and a single row resultset
START TRANSACTION;
SELECT nextSequence into @mine_to_use from sequences where sectionType=p_sectionType FOR UPDATE;
UPDATE sequences set nextSequence=nextSequence+1 where sectionType=p_sectionType;
COMMIT; -- get it and release INTENTION LOCK ASAP
set [email protected]_to_use; -- set the OUT parameter
select @mine_to_use as yourSeqNum; -- also return as a 1 column, 1 row resultset
END$$
DELIMITER ;
Test:
set @myNum:= -1;
call getNextSequence('Carburetor',@myNum);
+------------+
| yourSeqNum |
+------------+
| 4 |
+------------+
select @myNum; -- 4
Zmodyfikuj procedurę składowaną zgodnie z potrzebami, na przykład mając tylko 1 z 2 mechanizmów pobierania numeru sekwencji (parametr OUT lub zestaw wyników). Innymi słowy, łatwo jest porzucić OUT
koncepcja parametrów.
Jeśli nie zastosujesz się do zwolnienia LOCK jak najszybciej (co oczywiście nie jest potrzebne po aktualizacji) i przystąpisz do wykonywania czasochłonnego kodu przed wydaniem, po upływie limitu czasu dla innych klientów oczekujących na sekwencję mogą wystąpić następujące zdarzenia numer:
BŁĄD 1205 (HY000):Przekroczono limit czasu oczekiwania na blokadę; spróbuj ponownie uruchomić transakcję
Mam nadzieję, że to nigdy nie stanowi problemu.
show variables where variable_name='innodb_lock_wait_timeout';
Strona podręcznika MySQL dla innodb_lock_wait_timeout .
W moim systemie w tej chwili ma wartość 50 (sekund). Oczekiwanie dłużej niż sekundę lub dwie jest prawdopodobnie nie do zniesienia w większości sytuacji.
Interesująca podczas TRANSAKCJI jest również ta sekcja danych wyjściowych następującego polecenia:
SHOW ENGINE INNODB STATUS;