Mysql

MySQL儲存過程中的鎖定/事務

  • March 3, 2017

多個上游 Kapacitor 伺服器正在向負載平衡的 django 應用程序發送通知。如果所有上游伺服器都正常工作,應用程序將始終收到這些通知的副本(因為所有上游通知器都應該發送相同的通知;這只是為了冗餘)。我希望能夠過濾掉這些重複項。但是,由於 python 應用程序是負載平衡的,我們可以檢查這些重複項的唯一位置是在數據庫中。

這意味著我正在使用此儲存過程來控制應用程序邏輯,只需將帶有雜湊的數據插入數據庫並忽略重複項不是一種選擇(應用程序可能會根據警報的內容向某人發送 SMS 消息,所以我們絕對不想要騙子)

為此,我對消息進行散列處理,然後在數據庫中呼叫一個儲存過程,檢查過去 10 秒內收到的消息是否具有相同的散列。我想 99% 確定儲存過程在競爭條件下是安全的。

下面是一些似乎有效的 SQL 程式碼:

DROP PROCEDURE IF EXISTS openduty_check_duplicate;
CREATE PROCEDURE openduty_check_duplicate(IN new_hash CHAR(40))
 BEGIN
   DECLARE now TIMESTAMP;
   DECLARE is_duplicate INT;
   SELECT CURRENT_TIMESTAMP INTO now;
   DO GET_LOCK('openduty_check_duplicate', 10);
     START TRANSACTION;
       DELETE FROM openduty_dedup WHERE DATE_SUB(now, INTERVAL 10 SECOND) > triggered;
       SELECT COUNT(*) FROM openduty_dedup WHERE request_hash = new_hash INTO is_duplicate;
       IF is_duplicate = 0 THEN
         INSERT INTO openduty_dedup (request_hash, triggered) VALUES (new_hash, now);
       END IF;
     COMMIT;
   DO RELEASE_LOCK('openduty_check_duplicate');
   SELECT is_duplicate;
 END;

這會按預期工作嗎?我需要更改事務隔離級別嗎?在 MySQL 中有沒有更好的方法來做到這一點?

注意 我在一個環境中使用 MySQL 5.6,在另一個環境中使用 Amazon RDS,因此它應該盡可能兼容。

autocommit=1用, 用做這些PRIMARY KEY(request_hash)

DELETE FROM openduty_dedup
   WHERE triggered < NOW() - INTERVAL 10 SECOND
     AND request_hash = $hash;
INSERT IGNORE INTO openduty_dedup
   (request_hash, triggered)
   VALUES ($new_hash, NOW());

如果INSERT失敗,要麼是最近 10 秒內有條目,要麼是其他人剛剛潛入。如果您需要了解成功,請檢查Rows_affected(),它是特定於連接的,不需要在事務中。

不需要START TRANSACTION。無需預先計算“現在”。不需要GET_LOCK()。唯一的缺陷是硬編碼的 10 秒視窗。

引用自:https://dba.stackexchange.com/questions/166032