Veja a seguir um exemplo simples com um FOR UPDATE bloqueio de intenção . Um bloqueio em nível de linha com o mecanismo INNODB. A amostra mostra quatro linhas para as próximas sequências disponíveis que não sofrerão com a conhecida anomalia INNODB Gap (o caso em que as lacunas ocorrem após o uso com falha de um AUTO_INCREMENT).
Esquema:
-- 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);
Código de amostra:
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
Idealmente, você não tem uma
Line3
ou código inchado, o que atrasaria outros clientes em um Lock Wait. Ou seja, obtenha sua próxima sequência para usar, execute a atualização (a parte de incremento) e COMMIT
, O MAIS CEDO POSSÍVEL . O acima em um procedimento armazenado:
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 ;
Teste:
set @myNum:= -1;
call getNextSequence('Carburetor',@myNum);
+------------+
| yourSeqNum |
+------------+
| 4 |
+------------+
select @myNum; -- 4
Modifique o procedimento armazenado de acordo com suas necessidades, como ter apenas 1 dos 2 mecanismos para recuperar o número de sequência (o parâmetro OUT ou o conjunto de resultados). Em outras palavras, é fácil abandonar o
OUT
conceito de parâmetro. Se você não aderir ao lançamento o mais rápido possível do LOCK (o que obviamente não é necessário após a atualização) e continuar executando o código demorado, antes do lançamento, o seguinte poderá ocorrer após um período de tempo limite para outros clientes aguardando uma sequência número:
ERRO 1205 (HY000):Tempo limite de espera de bloqueio excedido; tente reiniciar a transação
Espero que isso nunca seja um problema.
show variables where variable_name='innodb_lock_wait_timeout';
Página de manual do MySQL para innodb_lock_wait_timeout .
No meu sistema no momento tem um valor de 50 (segundos). Uma espera de mais de um ou dois segundos é provavelmente insuportável na maioria das situações.
Também de interesse durante as TRANSAÇÕES é a seção da saída do seguinte comando:
SHOW ENGINE INNODB STATUS;