Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

Trường dòng tuần tự liền kề MySQL ngay cả khi xóa và chèn

Tôi biết có rất nhiều thứ ở đây. Tôi đã cố gắng ghi lại nó khá tốt bên trong mã và ở đây và ở đó. Nó sử dụng các thủ tục được lưu trữ. Bạn có thể kéo mã ra một cách tự nhiên và không sử dụng phương pháp đó. Nó sử dụng một bảng chính chứa các số tăng sẵn có tiếp theo. Nó sử dụng INNODB an toàn Khóa ý định cho đồng thời. Nó có một bảng tái sử dụng và các procs được lưu trữ để hỗ trợ nó.

Dù sao thì nó cũng không sử dụng bảng myTable . Nó được hiển thị ở đó cho trí tưởng tượng của riêng bạn dựa trên nhận xét dưới câu hỏi của bạn. Tóm tắt của điều đó là bạn biết rằng bạn sẽ có khoảng trống khi DELETE . Bạn muốn một số thời trang có trật tự để sử dụng lại những vị trí, những dãy số đó. Vì vậy, khi bạn DELETE một hàng, sử dụng các procs được lưu trữ tương ứng để thêm số đó. Đương nhiên, có một proc được lưu trữ để lấy số thứ tự tiếp theo để sử dụng lại và những thứ khác.

Với mục đích kiểm tra, sectionType của bạn ='thiết bị'

Và tốt nhất là nó đã được thử nghiệm!

Lược đồ:

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

Đã lưu trữ Proc: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'

Sau khi bạn gọi uspGetNextSequence (), bạn có TRÁCH NHIỆM để đảm bảo rằng trình tự đó #

được thêm vào myTable (bằng cách xác nhận nó), hoặc nếu nó không thành công, bạn chèn nó vào

bảng tái sử dụng với lệnh gọi tới uspAddToReuseList (). Không phải tất cả các lần chèn đều thành công. Tập trung vào phần này.

Bởi vì với mã này, bạn không thể "đặt" nó trở lại sequences bảng vì

đồng thời, những người dùng khác và phạm vi đã được chuyển qua. Vì vậy, đơn giản, nếu chèn không thành công,

đặt số vào reuseMe qua uspAddToReuseList ()

...

Đã lưu trữ Proc: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

Đã lưu trữ Proc: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();

Đã lưu trữ Proc: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();

Đã lưu trữ Proc: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);

Ý tưởng quy trình làm việc:

Hãy để GNS nghĩa là một cuộc gọi đến uspGetNextSequence() .

Hãy RS nghĩa là Sử dụng lại trình tự qua cuộc gọi tới uspGetOneToReuse()

Khi một INSERT mới là mong muốn, hãy gọi RS :

A. Nếu RS trả về -1 thì không có gì được sử dụng lại vì vậy hãy gọi GNS trả về N. Nếu bạn có thể INSERT thành công với myTable.seqNum=N với một xác nhận, bạn đã hoàn tất. Nếu bạn không thể INSERT thành công nó, sau đó gọi uspAddToReuseList(N) .

B. Nếu RS return> 0, lưu ý trong đầu bạn rằng vị trí có reuseMe.reused=1 , một điều tốt để ghi nhớ. Vì vậy, nó được giả định là đang trong quá trình được sử dụng lại thành công. Hãy gọi số thứ tự đó là N. Nếu bạn có thể INSERT thành công với myTable.seqNum=N với một xác nhận, bạn đã hoàn tất. Nếu bạn không thể INSERT thành công nó, sau đó gọi uspOoopsResetToAvail(N) .

Khi bạn cho là an toàn, hãy gọi uspCleanReuseList() làm vậy. Thêm DATETIME vào reuseMe bảng có thể là một ý tưởng hay, biểu thị khi một hàng từ myTable đang xóa ban đầu và gây ra reuseMe hàng để lấy INSERT ban đầu của nó .




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. PHP:Sử dụng một biến để giữ tên bảng và sử dụng biến đó trong các truy vấn

  2. vấn đề khung php yii với các đối tượng (2)

  3. Mysql:Chức năng tổng hợp không hoạt động nếu không có nhóm theo

  4. Trợ giúp với:ERROR 1025 (HY000):Lỗi khi đổi tên của .... (errno:150)

  5. Vấn đề của ký tự Ba Tư trong cơ sở dữ liệu mysql