簡體   English   中英

Mysql 並以原子方式執行存儲過程或 select 以原子方式更新

[英]Mysql and execute store procedure in atomic way or select update atomically

在 Mysql 中,我有兩個並發進程需要讀取一些行並根據條件更新標志。 我已經使用事務創建了一個存儲過程,但問題是有時這兩個進程會更新相同的行。

我有一個表狀態,我想讀取 15 行,其中標志 Reserved 為 true,而不是更新將標志 Reserved 設置為 False 的行。 更新的行必須返回給客戶端。

我的商店程序是:

CREATE DEFINER=`user`@`%` PROCEDURE `get_reserved`()
BEGIN
DECLARE tmpProfilePageId bigint;
DECLARE finished INTEGER DEFAULT 0;

DECLARE curProfilePage CURSOR FOR 
    SELECT ProfilePageId 
    FROM Status
    WHERE Reserved is false and ((timestampdiff(HOUR, UpdatedTime, NOW()) >= 23) or UpdatedTime is NULL)
    ORDER BY UpdatedTime ASC
    LIMIT 15;
DECLARE CONTINUE HANDLER 
    FOR NOT FOUND SET finished = 1;
    
DECLARE EXIT HANDLER FOR SQLEXCEPTION ROLLBACK;
DECLARE EXIT HANDLER FOR SQLWARNING ROLLBACK;

START TRANSACTION;

DROP TEMPORARY TABLE IF EXISTS TmpAdsProfile;
CREATE TEMPORARY TABLE TmpAdsProfile(Id INT PRIMARY KEY AUTO_INCREMENT, ProfilePageId BIGINT);

OPEN curProfilePage;

getProfilePage: LOOP
    FETCH curProfilePage INTO tmpProfilePageId;
    IF finished = 1 THEN LEAVE getProfilePage;
    END IF;
    UPDATE StatusSET Reserved = true WHERE ProfilePageId = tmpProfilePageId;
    INSERT INTO TmpAdsProfile (ProfilePageId) VALUES (tmpProfilePageId);
END LOOP getProfilePage;

CLOSE curProfilePage;

SELECT ProfilePageId FROM TmpAdsProfile;

COMMIT;

END

無論如何,如果我執行兩個調用此存儲過程的並發進程,有時它們會更新相同的行。

如何以原子方式執行存儲過程?

稍微簡化一下並使用FOR UPDATE 這將鎖定您要更改的行,直到您提交事務。 您可以完全擺脫 cursor。 像這樣的東西,沒有調試!

START TRANSACTION;

CREATE OR REPLACE TEMPORARY TABLE TmpAdsProfile AS
SELECT ProfilePageId 
  FROM Status
 WHERE Reserved IS false 
   AND ((timestampdiff(HOUR, UpdatedTime, NOW()) >= 23) OR UpdatedTime IS NULL)
 ORDER BY UpdatedTime ASC
 LIMIT 15 
   FOR UPDATE; 

 UPDATE Status SET Reserved = true 
  WHERE ProfilePageId IN (SELECT ProfilePageId FROM TmpAdsProfile);
 
COMMIT;

SELECT ProfilePageId FROM TmpAdsProfile;

該臨時表將永遠只有十五行。 所以索引和 PK 以及所有這些都是不必要的。 因此,您可以使用CREATE... AS SELECT...在 go 中創建和填充表。

並且,考慮重鑄您的 UpdatedTime 過濾器,以便它可以使用索引。

AND (UpdatedTime <= NOW() - INTERVAL 23 HOUR OR UpdatedTime IS NULL)

SELECT 查詢的適當索引是

CREATE INDEX status_update ON Status (Reserved, UpdatedTime, ProfilePageId);

您的 SELECT 操作越快,您的交易時間就越短,因此您的整體性能就越好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM