Mysql
 sql >> Datenbank >  >> RDS >> Mysql

mysql - Erstellen eines Mechanismus ähnlich den Sequenzen von Oracle

Das Folgende ist ein einfaches Beispiel mit einer FOR UPDATE Absichtssperre . Eine Sperre auf Zeilenebene mit der INNODB-Engine. Das Beispiel zeigt vier Zeilen für die nächsten verfügbaren Sequenzen, die nicht unter der bekannten INNODB-Lückenanomalie leiden (der Fall, in dem Lücken nach fehlgeschlagener Verwendung eines AUTO_INCREMENT auftreten).

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

Beispielcode:

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

Idealerweise haben Sie keine Line3 oder aufgeblähter Code überhaupt, der andere Clients bei einem Lock Wait verzögern würde. Das heißt, holen Sie sich Ihre nächste zu verwendende Sequenz, führen Sie die Aktualisierung durch (den inkrementierenden Teil) und COMMIT , so bald wie möglich .

Das Obige in einer gespeicherten Prozedur:

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

Ändern Sie die gespeicherte Prozedur entsprechend Ihren Anforderungen, z. B. nur einen der beiden Mechanismen zum Abrufen der Sequenznummer (entweder den OUT-Parameter oder die Ergebnismenge). Mit anderen Worten, es ist einfach, den OUT fallen zu lassen Parameterkonzept.

Wenn Sie sich nicht an die ASAP-Veröffentlichung von LOCK halten (die nach dem Update offensichtlich nicht erforderlich ist) und vor der Veröffentlichung zeitaufwändigen Code ausführen, kann nach einer Zeitüberschreitung für andere Clients, die auf eine Sequenz warten, Folgendes auftreten Zahl:

FEHLER 1205 (HY000):Sperrwartezeit überschritten; Versuchen Sie, die Transaktion neu zu starten

Hoffentlich ist das nie ein Problem.

show variables where variable_name='innodb_lock_wait_timeout';

MySQL-Handbuchseite für innodb_lock_wait_timeout .

Auf meinem System hat es im Moment einen Wert von 50 (Sekunden). Eine Wartezeit von mehr als ein oder zwei Sekunden ist in den meisten Situationen wahrscheinlich unerträglich.

Bei TRANSAKTIONEN ist auch der Abschnitt der Ausgabe des folgenden Befehls von Interesse:

SHOW ENGINE INNODB STATUS;