Mysql

避免並發插入死鎖

  • September 18, 2021

我試圖避免未來的問題。

表有 2 個欄位:

id -> bigint Primary key

hash -> varchar(65) unique key

將有並發插入到表中以進行雜湊。我需要最後一個插入 id

所以問題: INSERT INTO table (hash) VALUES(blah) ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id) 如果有 30-50 個執行緒會產生死鎖,這些執行緒很有可能會嘗試插入相同的 blah?

或者我需要做什麼: SELECT id FROM table WHERE hash=blah 如果存在的話

如果不存在:

INSERT IGNORE INTO table (hash) VALUES(blah);

SELECT id FROM table WHERE hash=blah

編輯:這是表格:

CREATE TABLE `hash_list` (
 `id` bigint NOT NULL AUTO_INCREMENT,
 `hash` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
 PRIMARY KEY (`id`),
 UNIQUE KEY `hash_UNIQUE` (`hash`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

我無法控制雜湊。我只需要儲存一次雜湊並多次獲取 id,以便它可以在應用程序的其他地方使用。沒有死鎖。通過這種方式,我節省了儲存空間,隨著時間的推移將變得非常重要。

編輯 2:由於 ROW_COUNT() 建議,我已將 danblack 的答案標記為已接受。但里克詹姆斯也有有效的觀點。兩個答案都很棒!

編輯 3:有趣的是,有 100 多個加我看到 0 個死鎖。

所以總結一下這個問題,輸入是一個需要儲存的雜湊。並且需要該 ID 的 auto_increment。

你做了正確的事並做hash了一個unique key.

INSERT IGNORE INTO hash_list (hash) VALUES(?);

是正確的。在應用程序 API 或 SQL ( ROW_COUNT()) 中,您將獲得受影響的行。0 表示它已經存在。

如果它已經存在,您需要獲取id

SELECT id FROM hash_list WHERE hash=?

如果ROW_COUNT()是 1,那麼LAST_INSERT_ID()(兩者都在應用程序 API 中,因此不需要單獨的查詢)就是id您需要的。

建議使用二進制類型的雜湊,因為它的名稱不會是 utf8mb4。

根據您是否需要插入更多或通過 id 檢索雜湊,您可以按如下方式製作hash主鍵和id唯一AUTO_INCREMENT鍵:

CREATE TABLE `hash_list` (
 `id` bigint NOT NULL AUTO_INCREMENT,
 `hash` varbinary(45),
 PRIMARY KEY (`hash`),
 UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB

hash無論提供的表結構是唯一鍵還是主鍵,上述查詢都將起作用。該AUTO_INCREMENT列需要建立索引。

參考:小提琴

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