sql >> データベース >  >> RDS >> Mysql

削除および挿入時でもMySQL連続行フィールド

    ここにはたくさんあることを知っています。私はそれをコード内とあちこちでかなりうまく文書化しようとしました。ストアドプロシージャを使用します。あなたは自然にコードを引き出して、その方法を使わないことができます。次に使用可能なインクリメンターを格納するメインテーブルを使用します。安全な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. MAMPでLaravelを使用してPostgreSQLをセットアップする

    2. SQLServerデータベースの列を含むすべてのデフォルトの制約を一覧表示する方法-SQLServer/TSQLチュートリアルパート92

    3. MYSQL:レコードがすでに存在する場合はレコードを挿入します更新レコード

    4. 複式簿記からの報告