Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

Bidang Baris Sekuensial Bersebelahan MySQL bahkan saat dihapus dan disisipkan

Saya tahu ada banyak hal di sini. Saya mencoba mendokumentasikannya dengan baik di dalam kode dan di sana-sini. Ini menggunakan Prosedur Tersimpan. Anda secara alami dapat mengeluarkan kode dan tidak menggunakan metode itu. Ini menggunakan tabel utama yang menampung inkremental berikutnya yang tersedia. Menggunakan INNODB yang aman Intention Locks untuk konkurensi. Ini memiliki tabel penggunaan kembali dan procs tersimpan untuk mendukungnya.

Itu sama sekali tidak menggunakan tabel myTable . Itu ditampilkan di sana untuk imajinasi Anda sendiri berdasarkan komentar di bawah pertanyaan Anda. Ringkasannya adalah Anda tahu bahwa Anda akan memiliki celah pada DELETE . Anda ingin beberapa mode teratur untuk menggunakan kembali slot itu, nomor urut itu. Jadi, ketika Anda DELETE berturut-turut, gunakan procs yang disimpan sesuai untuk menambahkan nomor itu. Tentu saja ada proc yang tersimpan untuk mendapatkan nomor urut berikutnya untuk digunakan kembali dan hal-hal lain.

Untuk tujuan pengujian, sectionType . Anda ='perangkat'

Dan yang terbaik dari semuanya itu telah diuji!

Skema:

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

Proc Tersimpan: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'

Setelah Anda memanggil uspGetNextSequence() itu adalah TANGGUNG JAWAB Anda untuk memastikan bahwa urutan #

ditambahkan ke myTable (dengan mengonfirmasinya), atau jika gagal, Anda memasukkannya ke dalam

tabel reuse dengan panggilan ke uspAddToReuseList(). Tidak semua penyisipan berhasil. Fokus pada bagian ini.

Karena dengan kode ini Anda tidak dapat "memasukkannya" kembali ke sequences tabel karena

konkurensi, pengguna lain, dan rentang yang sudah dilewati. Jadi, sederhananya, jika penyisipan gagal,

masukkan nomornya ke reuseMe melalui uspAddToReuseList()

...

Proc Tersimpan: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

Proc Tersimpan: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();

Proc Tersimpan: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();

Proc Tersimpan: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);

Ide alur kerja:

Biarkan GNS berarti panggilan ke uspGetNextSequence() .

Biarkan RS berarti Menggunakan Ulang Urutan melalui panggilan ke uspGetOneToReuse()

Saat INSERT baru diinginkan, hubungi RS :

A. Jika RS mengembalikan -1 maka tidak ada yang dapat digunakan kembali jadi panggil GNS yang mengembalikan N. Jika Anda berhasil INSERT dengan myTable.seqNum=N dengan konfirmasi, Anda selesai. Jika Anda tidak berhasil INSERT itu, lalu panggil uspAddToReuseList(N) .

B. Jika RS mengembalikan> 0, perhatikan di kepala Anda bahwa slot memiliki reuseMe.reused=1 , hal yang baik untuk diingat. Jadi diasumsikan dalam proses berhasil digunakan kembali. Sebut saja nomor urut itu N. Jika Anda berhasil INSERT dengan myTable.seqNum=N dengan konfirmasi, Anda selesai. Jika Anda tidak berhasil INSERT itu, lalu panggil uspOoopsResetToAvail(N) .

Bila Anda menganggap aman untuk memanggil uspCleanReuseList() melakukannya. Menambahkan DATETIME ke reuseMe tabel mungkin ide yang bagus, yang menunjukkan ketika baris dari myTable awalnya menghapus dan menyebabkan reuseMe baris untuk mendapatkan INSERT aslinya .




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Pembaruan bersamaan MySQL

  2. Mengunggah gambar di CKEditor tanpa menggunakan plugin

  3. Menginstal WordPress 5 di ZEIT Sekarang dengan Hosting MySQL

  4. Cara mendapatkan nilai dari tabel berdasarkan Preferensi

  5. SELECT vs UPDATE kinerja dengan indeks