避免並發插入死鎖
我試圖避免未來的問題。
表有 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
列需要建立索引。參考:小提琴