Mysql
 sql >> Database >  >> RDS >> Mysql

mysql - creare un meccanismo simile alle sequenze di Oracle

Quello che segue è un semplice esempio con un FOR UPDATE blocco delle intenzioni . Un blocco a livello di riga con il motore INNODB. L'esempio mostra quattro righe per le successive sequenze disponibili che non risentiranno della nota INNODB Gap Anomaly (il caso in cui si verificano interruzioni dopo l'utilizzo non riuscito di un AUTO_INCREMENT).

Schema:

-- 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);

Codice di esempio:

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 non hai una Line3 o codice bloaty che ritarderebbe altri client in un'attesa di blocco. Ciò significa che ottieni la tua prossima sequenza da usare, esegui l'aggiornamento (la parte incrementale) e COMMIT , Al più presto .

Quanto sopra in una procedura memorizzata:

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

Modificare la procedura memorizzata in base alle proprie esigenze, ad esempio avere solo 1 dei 2 meccanismi per recuperare il numero di sequenza (il parametro OUT o il set di risultati). In altre parole, è facile abbandonare OUT concetto di parametro.

Se non aderisci al rilascio ASAP del LOCK (che ovviamente non è necessario dopo l'aggiornamento) e procedi a eseguire codice che richiede tempo, prima del rilascio, dopo un periodo di timeout per altri client in attesa di una sequenza può verificarsi quanto segue numero:

ERRORE 1205 (HY000):Timeout attesa blocco superato; prova a riavviare la transazione

Speriamo che questo non sia mai un problema.

show variables where variable_name='innodb_lock_wait_timeout';

Pagina del manuale MySQL per innodb_lock_wait_timeout .

Sul mio sistema al momento ha un valore di 50 (secondi). Un'attesa di più di un secondo o due è probabilmente insopportabile nella maggior parte delle situazioni.

Interessante anche durante le TRANSAZIONI è quella sezione dell'output del seguente comando:

SHOW ENGINE INNODB STATUS;