InnoDB:使用插入选择的自定义自动增量.会出现重复键错误吗? [英] InnoDB: custom auto-increment using insert select. Can there be duplicate-key error?

查看:52
本文介绍了InnoDB:使用插入选择的自定义自动增量.会出现重复键错误吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个像这样的表: idx(PK)clmn_1

I have a table like: idx (PK) clmn_1

都是INT. idx 不是定义为自动增量,但我正在尝试模拟它.至插入到此表中,我正在使用:

Both are INTs. idx is not defined as auto-increment, but I am trying to simulate it. To insert into this table, I am using:

"INSERT INTO  my_tbl (idx, clmn_1)   \
 SELECT IFNULL(MAX(idx), 0) + 1, %s  \
 FROM my_tbl", val_clmn_1

现在,这可行.我有关于原子性的查询.由于我读取然后插入到同一张表中,因此当同时发生多个插入时,可能会出现重复键错误?

Now, this works. The query that I have is about atomicity. Since I read and then insert to the same table, when multiple inserts happen simultaneous can there potentially be a duplicate-key error?

然后,我如何自己测试呢?

And, how can I test it myself?

我正在使用Percona XtraDB服务器5.5.

I am using Percona XtraDB server 5.5.

推荐答案

这不是一个好的解决方案,因为它在执行SELECT时会在my_tbl上创建一个共享锁.任意数量的线程可以同时拥有一个共享锁,但是它会阻塞并发写入锁.因此,这将导致插入序列化,等待SELECT完成.

This is not a good solution, because it creates a shared lock on my_tbl while it's doing the SELECT. Any number of threads can have a shared lock concurrently, but it blocks concurrent write locks. So this causes inserts to become serialized, waiting for the SELECT to finish.

您可以观察到此锁定.在一个会话中启动此查询:

You can observe this lock. Start this query in one session:

INSERT INTO  my_tbl (idx, clmn_1) 
 SELECT IFNULL(MAX(idx), 0) + 1, 1234+SLEEP(60) 
 FROM my_tbl;

然后转到另一个会话并运行innotop并查看锁定屏幕(按"L"键).您将看到这样的输出:

Then go to another session and run innotop and view the locking screen (press key 'L'). You'll see output like this:

___________________________________ InnoDB Locks ___________________________________
ID  Type    Waiting  Wait   Active  Mode  DB    Table   Index    Ins Intent  Special
61  TABLE         0  00:00   00:00  IS    test  my_tbl                    0         
61  RECORD        0  00:00   00:00  S     test  my_tbl  PRIMARY           0         

这就是自动递增机制按其工作方式起作用的原因.无论事务是否隔离,插入线程都会简短地锁定表,只是增加自动递增编号.这是非常快的.然后释放该锁,允许其他线程立即进行.同时,第一个线程尝试完成其插入.

This is why the auto-increment mechanism works the way it does. Regardless of transaction isolation, the insert thread locks the table briefly only to increment the auto-inc number. This is extremely quick. Then the lock is released, allowing other threads to proceed immediately. Meanwhile, the first thread attempts to finish its insert.

请参见 http://dev.mysql.com/doc/refman/5.5/en/innodb-auto-increment-handling.html 了解有关自动增量锁定的更多详细信息.

See http://dev.mysql.com/doc/refman/5.5/en/innodb-auto-increment-handling.html for more details about auto-increment locking.

我不确定为什么要模拟自动增量行为,而不是仅仅将列定义为自动增量列.您可以将现有表更改为自动递增.

I'm not sure why you want to simulate auto-increment behavior instead of just defining the column as an auto-increment column. You can change an existing table to be auto-incrementing.

发表您的评论

即使将PK声明为自动增量,您仍然可以指定一个值.仅当您在IN​​SERT中指定PK列,或者您将 NULL DEFAULT 作为其值时,自动增量才会启动

Even if a PK is declared as auto-increment, you can still specify a value. The auto-incrementation only kicks in if you don't specify the PK column in the INSERT, or you specify NULL or DEFAULT as its value.

CREATE TABLE foo (id INT AUTO_INCREMENT PRIMARY KEY, c CHAR(1));
INSERT INTO foo (id, c) VALUES (123, 'x'); -- inserts value 123
INSERT INTO foo (id, c) VALUES (DEFAULT, 'y'); -- inserts value 124
INSERT INTO foo (id, c) VALUES (42, 'n'); -- inserts specified value 42
INSERT INTO foo (c) VALUES ('Z'); -- inserts value 125
REPLACE INTO foo (id, c) VALUES (125, 'z'); -- changes existing row with id=125


发表您的评论


Re your comment:

START TRANSACTION; 
SELECT IFNULL(MAX(idx), 0)+1 FROM my_tbl FOR UPDATE; 
INSERT INTO my_tbl (idx, clmn_1) VALUES (new_idx_val, some_val); 
COMMIT; 

这实际上比您的第一个想法差,因为现在 SELECT ... FOR UPDATE 创建一个X锁而不是S锁.

This is actually worse than your first idea, because now the SELECT...FOR UPDATE creates an X lock instead of an S lock.

您真的不应该尝试重塑AUTO-INCREMENT的行为,因为任何SQL解决方案都受ACID属性的限制.自动递增功能必须在ACID之外起作用.

You should really not try to re-invent the behavior of AUTO-INCREMENT, because any SQL solution is limited by ACID properties. Auto-inc necessarily works outside of ACID.

如果您需要自动更正现有行,请使用替换或插入...在重复的密钥更新上.

If you need to correct existing rows atomically, use either REPLACE or INSERT...ON DUPLICATE KEY UPDATE.

这篇关于InnoDB:使用插入选择的自定义自动增量.会出现重复键错误吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆