sql >> Databasteknik >  >> RDS >> Mysql

mysql - gör en mekanism som liknar Oracles sekvenser

Följande är ett enkelt exempel med ett FÖR UPPDATERING avsiktslås . Ett radnivålås med INNODB-motorn. Provet visar fyra rader för nästa tillgängliga sekvenser som inte kommer att drabbas av den välkända INNODB Gap Anomaly (fallet där luckor uppstår efter misslyckad användning av en 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);

Exempelkod:

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

Helst har du ingen Line3 eller överhuvudtaget uppblåst kod som skulle försena andra klienter på en Lock Wait. Det betyder, skaffa din nästa sekvens att använda, utför uppdateringen (den inkrementerande delen) och COMMIT , ASAP .

Ovanstående i en lagrad procedur:

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

Ändra den lagrade proceduren i enlighet med dina behov, som att bara ha en av de två mekanismerna för att hämta sekvensnumret (antingen OUT-parametern eller resultatuppsättningen). Med andra ord är det lätt att ta bort OUT parameterkoncept.

Om du inte följer ASAP-releasen av LOCK (vilket uppenbarligen inte behövs efter uppdateringen), och fortsätter att utföra tidskrävande kod, före releasen, kan följande inträffa efter en timeout-period för andra klienter som väntar på en sekvens nummer:

FEL 1205 (HY000):Tidsgränsen för låst väntetid har överskridits; försök att starta om transaktionen

Förhoppningsvis är detta aldrig ett problem.

show variables where variable_name='innodb_lock_wait_timeout';

MySQL-manualsida för innodb_lock_wait_timeout .

På mitt system för tillfället har det ett värde på 50 (sekunder). En väntan på mer än en sekund eller två är förmodligen outhärdlig i de flesta situationer.

Också av intresse under TRANSACTIONS är den delen av utdata från följande kommando:

SHOW ENGINE INNODB STATUS;



  1. Hur man använder Global Temporary Table i Oracle Procedur?

  2. ScaleGrid rankad bland de 100 bästa molntjänstleverantörerna

  3. Hur grupperar jag efter vecka i MySQL?

  4. Hur man använder rollerna som har ändrats i MySQL 8.0