2017-08-04 72 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