2017-08-04 76 views
0

names是每一個獨特的名稱映射到一個ID表:添加到或唯一鍵的SQL表中檢索和值

CREATE TABLE names (
    name  VARCHAR(20) NOT NULL, 
    name_id INT   NOT NULL AUTO_INCREMENT, 
    PRIMARY KEY (name), 
    UNIQUE (name_id) 
) ENGINE=InnoDB 

如果「foobar的」已經存儲在names,我想其name_id。否則,我想存儲它並獲取爲其生成的name_id

如何做到這一點,處理兩個線程競爭加入'foobar'的可能性? (注:我們從來沒有從該表中刪除。)

於MyISAM我寫道:

GET_LOCK('foobar'); 
SELECT name_id FROM names WHERE name = 'foobar'; 
if name wasn't found 
    INSERT INTO names SET name='foobar'; 
    SELECT LAST_INSERT_ID(); -- that is, name_id 
RELEASE_LOCK('foobar'); 

但是,我對如何實現這一目標使用事務和行級鎖定在InnoDB中非常不清楚。

更新: mySQL要求AUTO_INCREMENT僅用於PK。我正在使用MariaDB,它只需要將AUTO_INCREMENT列定義爲鍵。相應地更新示例。

+0

用'START TRANSACTION'和'COMMIT'替換'GET_LOCK'和'RELEASE_LOCK'。 – Barmar

+0

@Barmar當第二個線程執行INSERT並獲得DUPLICATE KEY違例時會發生什麼?或者是第二個線程在START TRANSACTION被阻止,直到第一個線程結束交易? – Chap

+0

我認爲應該阻止第二個線程。但嘗試一下,看看。 – Barmar

回答

1

嘗試以下操作:

​​

你不需要明確的事務是否自動提交已啓用,將有圍繞INSERT IGNORE查詢的隱式事務,使其原子。

ROW_COUNT()會告訴你它是否能夠插入新行;如果名稱可用,將爲1,如果發現重複,則0,因此不能插入行。

+0

這工作正常。但是,我將在INSERT之前使用SELECT來實現,因爲在這一點上,95%的時間名稱已經存在,而INSERT通常會失敗。 – Chap

+0

所以'SELECT',如果找不到'INSERT IGNORE',那麼再次測試結果和'SELECT'?基於前提的合理性。 – Barmar