Mysql 重复密钥更新时插入的线程安全性

Mysql 重复密钥更新时插入的线程安全性,mysql,concurrency,Mysql,Concurrency,MySQL语句: 插入。。。在重复密钥更新时… 看起来像一条应该是线程安全的语句(从某种意义上说,在执行过程中不会对同一数据进行并发查询)。但另一方面,它可以在内部分解为insert和update语句,我想知道它是否仍然保证线程安全 我的意思是,例如,insert和update之间是否存在一个delete,它来自一个并发线程,会导致更新失败 我认为insert on duplicate key update应该是线程安全的,但文档似乎没有明文说明。有人能提供一个关于这个主题的证明链接吗?它是如何

MySQL语句:

插入。。。在重复密钥更新时…

看起来像一条应该是线程安全的语句(从某种意义上说,在执行过程中不会对同一数据进行并发查询)。但另一方面,它可以在内部分解为
insert
update
语句,我想知道它是否仍然保证线程安全

我的意思是,例如,
insert
update
之间是否存在一个
delete
,它来自一个并发线程,会导致
更新失败


我认为
insert on duplicate key update
应该是线程安全的,但文档似乎没有明文说明。有人能提供一个关于这个主题的证明链接吗?它是如何在内部实现的?

RDBMS使用锁和隔离级别来控制并行运行的会话如何访问相同的数据。没有线程安全,也没有会话安全。只有并发控制

如果使用myisam表类型,则所有数据修改语句(myisam可以在有限的情况下执行并发插入,但删除操作始终需要表锁)。因此,删除不能干扰插入。。。在重复密钥更新时…

如果使用innodb表类型,那么情况会更复杂一些,因为它应用了行级锁。正如mysql手册上所说:

插入。。。重复密钥更新与简单插入的不同之处在于,发生重复密钥错误时,将在要更新的行上放置独占锁而不是共享锁。对重复的主键值采用独占索引记录锁。对于重复的唯一密钥值,将使用独占的下一个密钥锁

因此,首先mysql锁定插入的新记录。如果出现重复密钥错误,则只有在该错误发生时,重复记录才会被锁定。从技术上讲,在重复密钥错误和对重复记录放置独占锁之间,delete语句可能会删除重复记录。但是,这不会使update语句失败。它不会更新任何记录

但这需要delete语句的时间安排非常准确


插入。。。在重复密钥更新时…
语句可能会失败,前提是delete语句在重复密钥错误后获得了重复记录上的独占锁,并且保持锁的时间太长,以至于insert的事务超时。

我想锁定将开始,另一个查询将不得不等待。这正是发生的情况,系统将该行锁定为一个事务,并且在更新完成之前不会解锁。DRDBMS使用锁和隔离级别来控制并行运行的会话如何访问相同的数据。没有线程安全这样的东西。另外,您应该指定您所指的mysql中的哪个存储引擎。Myisam和innodb实现的功能完全不同。我同意,在这种情况下,“线程安全”一词可能并不准确。也许我应该使用“会话安全”,但听起来很奇怪:)无论如何,我希望你明白我的意思。至于RDBMS,我目前正在使用InnoDB,但我想知道其他系统是如何工作的。谢谢你的详细回答。原来锁是在内部使用的,到处都是!我曾经认为,重复密钥更新时插入是一种无锁、无事务的方法,因此是控制并发访问的廉价方法(就避免等待造成的瓶颈而言)。现在看来,它不是所有的锁和便宜。如果我正在构建一个低延迟的系统,那么这仍然是在MySQL上进行“升级”的最佳方式吗?很抱歉,如果你有一个新问题,那么你需要将其作为一个新问题发布。但是首先搜索答案,因为mysql中有几十个关于upsert的问题,比较了执行upsert的不同方法。此外,这意味着我的原始问题的答案是否定的,也就是说,重复密钥更新时插入不能保证与并发会话分离。因此,如果第一次插入失败,它相当于(在并发意义上)发送两个单独的语句INSERT和UPDATE。这对吗?不,这不对。请参阅我的答案中引用的部分。它的实现(独占锁而不是共享锁)有所不同,但从客户机的角度来看,语句结束时没有记录(删除)的可能性仍然没有完全消除,尽管可能性可能会降低。对的