Mysql
 sql >> база данни >  >> RDS >> Mysql

MySQL Contiguous Sequential Rows Field дори при изтриване и вмъкване

Знам, че тук има много. Опитах се да го документирам доста добре в кода и тук и там. Той използва съхранени процедури. Можете естествено да изтеглите кода и да не използвате този метод. Той използва основна таблица, която съдържа следващите налични инкрементори. Той използва безопасен INNODB Блокировки на намерението за едновременност. Има таблица за повторно използване и съхранени процедури, за да го поддържа.

По никакъв начин не използва таблицата myTable . Там е показано за вашето собствено въображение въз основа на коментари под въпроса ви. Обобщението на това е, че знаете, че ще имате пропуски при DELETE . Искате някакъв подреден начин да използвате повторно тези слотове, тези поредни номера. И така, когато DELETE ред, използвайте съответно съхранените процедури, за да добавите това число. Естествено има съхранена процедура за получаване на следващия пореден номер за повторно използване и други неща.

За целите на тестването, вашият sectionType ='устройства'

И най-доброто от всичко е тествано!

Схема:

create table myTable
(   -- your main table, the one you cherish
    `id` int auto_increment primary key, -- ignore this
    `seqNum` int not null, -- FOCUS ON THIS
    `others` varchar(100) not null
) ENGINE=InnoDB;

create table reuseMe
(   -- table for sequence numbers to reuse
    `seqNum` int not null primary key, -- FOCUS ON THIS
    `reused` int not null -- 0 upon entry, 1 when used up (reused)
    -- the primary key enforces uniqueness
) ENGINE=InnoDB;;

CREATE TABLE `sequences` (
    -- table of sequence numbers system-wide
    -- this is the table that allocates the incrementors to you
    `id` int NOT NULL AUTO_INCREMENT,
    `sectionType` varchar(200) NOT NULL,
    `nextSequence` int NOT NULL,
    PRIMARY KEY (`id`),
    UNIQUE KEY `sectionType` (`sectionType`)
) ENGINE=InnoDB;
INSERT sequences(sectionType,nextSequence) values ('devices',1); -- this is the focus
INSERT sequences(sectionType,nextSequence) values ('plutoSerialNum',1); -- not this
INSERT sequences(sectionType,nextSequence) values ('nextOtherThing',1); -- not this
-- the other ones are conceptuals for multi-use of a sequence table

Съхранена процедура:uspGetNextSequence

DROP PROCEDURE IF EXISTS uspGetNextSequence;
DELIMITER $$
CREATE PROCEDURE uspGetNextSequence(p_sectionType varchar(200))
BEGIN
    -- a stored proc to manage next sequence numbers handed to you.
    -- driven by the simple concept of a name. So we call it a section type.
    -- uses SAFE INNODB Intention Locks to support concurrency
    DECLARE valToUse INT;

    START TRANSACTION;
    SELECT nextSequence into valToUse from sequences where sectionType=p_sectionType FOR UPDATE;
    IF valToUse is null THEN
        SET valToUse=-1;
    END IF;
    UPDATE sequences set nextSequence=nextSequence+1 where sectionType=p_sectionType;
    COMMIT; -- get it and release INTENTION LOCK ASAP
    SELECT valToUse as yourSeqNum; -- return as a 1 column, 1 row resultset
END$$
DELIMITER ;
-- ****************************************************************************************
-- test:
call uspGetNextSequence('devices'); -- your section is 'devices'

След като извикате uspGetNextSequence(), ваша е ОТГОВОРНОСТТА да гарантирате, че тази последователност #

или се добавя в myTable (като го потвърдите), или че ако не успее, вие го вмъкнете в

таблицата за повторно използване с извикване на uspAddToReuseList(). Не всички вмъквания са успешни. Фокусирайте се върху тази част.

Тъй като с този код не можете да го "поставите" обратно в sequences таблица поради

паралелност, други потребители и диапазонът, който вече е преминат. Така че, просто, ако вмъкването се провали,

поставете номера в reuseMe чрез uspAddToReuseList()

...

Съхранена процедура:uspAddToReuseList:

DROP PROCEDURE IF EXISTS uspAddToReuseList;
DELIMITER $$
CREATE PROCEDURE uspAddToReuseList(p_reuseNum INT)
BEGIN
    -- a stored proc to insert a sequence num into the reuse list
    -- marks it available for reuse (a status column called `reused`)
    INSERT reuseMe(seqNum,reused) SELECT p_reuseNum,0; -- 0 means it is avail, 1 not
END$$
DELIMITER ;
-- ****************************************************************************************
-- test:
call uspAddToReuseList(701); -- 701 needs to be reused

Съхранена процедура:uspGetOneToReuse:

DROP PROCEDURE IF EXISTS uspGetOneToReuse;
DELIMITER $$
CREATE PROCEDURE uspGetOneToReuse()
BEGIN
    -- a stored proc to get an available sequence num for reuse
    -- a return of -1 means there aren't any
    -- the slot will be marked as reused, the row will remain
    DECLARE retNum int; -- the seq number to return, to reuse, -1 means there isn't one

    START TRANSACTION;

    -- it is important that 0 or 1 rows hit the following condition
    -- also note that FOR UPDATE is the innodb Intention Lock
    -- The lock is for concurrency (multiple users at once)
    SELECT seqNum INTO retNum 
    FROM reuseMe WHERE reused=0 ORDER BY seqNum LIMIT 1 FOR UPDATE;

    IF retNum is null THEN
        SET retNum=-1;
    ELSE 
        UPDATE reuseMe SET reused=1 WHERE seqNum=retNum; -- slot used
    END IF;
    COMMIT; -- release INTENTION LOCK ASAP

    SELECT retNum as yoursToReuse; -- >0 or -1 means there is none
END$$
DELIMITER ;
-- ****************************************************************************************
-- test:
call uspGetOneToReuse();

Съхранена процедура:uspCleanReuseList:

DROP PROCEDURE IF EXISTS uspCleanReuseList;
DELIMITER $$
CREATE PROCEDURE uspCleanReuseList()
BEGIN
    -- a stored proc to remove rows that have been successfully reused
    DELETE FROM reuseMe where reused=1;
END$$
DELIMITER ;
-- ****************************************************************************************
-- test:
call uspCleanReuseList();

Съхранена процедура:uspOoopsResetToAvail:

DROP PROCEDURE IF EXISTS uspOoopsResetToAvail;
DELIMITER $$
CREATE PROCEDURE uspOoopsResetToAvail(p_reuseNum INT)
BEGIN
    -- a stored proc to deal with a reuse attempt (sent back to you)
    -- that you need to reset the number as still available, 
    -- perhaps because of a failed INSERT when trying to reuse it
    UPDATE reuseMe SET reused=0 WHERE seqNum=p_reuseNum;
END$$
DELIMITER ;
-- ****************************************************************************************
-- test:
call uspOoopsResetToAvail(701);

Идеи за работен процес:

Нека GNS означава извикване на uspGetNextSequence() .

Нека RS означава последователност за повторно използване чрез извикване на uspGetOneToReuse()

Когато нов INSERT е желано, обадете се на RS :

A. Ако RS връща -1, тогава нищо не трябва да се използва повторно, така че извикайте GNS който връща N. Ако можете успешно INSERT с myTable.seqNum=N с потвърждение сте готови. Ако не можете успешно INSERT го, след това извикайте uspAddToReuseList(N) .

B. Ако RS връща> 0, имайте предвид, че слотът има reuseMe.reused=1 , добре е да запомните. Така че се предполага, че е в процес на успешно повторно използване. Нека наречем този пореден номер N. Ако можете успешно INSERT с myTable.seqNum=N с потвърждение сте готови. Ако не можете успешно INSERT го, след това извикайте uspOoopsResetToAvail(N) .

Когато сметнете за безопасно да извикате uspCleanReuseList() Направи го. Добавяне на DATETIME към reuseMe таблица може да е добра идея, обозначавайки ред от myTable първоначално изтриваше и причиняваше reuseMe ред, за да получите оригиналния си INSERT .




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Трябва ли да се избягва MEDIUMINT в MySQL?

  2. preg_replace() не намира краен разделител?

  3. Задаване на колона като времева марка в MySql Workbench?

  4. mysql - мога ли да попитам колко connect_errors даде даден хост?

  5. Строг режим на база данни на Laravel