当前位置: 首页 > 知识库问答 >
问题:

如何锁定尚不存在的InnoDB行?

宗政松
2023-03-14

如何保证我可以搜索我的数据库中是否存在用户名,然后将该用户名作为新行插入数据库,而不会在SELECTINSERT语句之间进行任何拦截?

几乎就像我锁定了一个不存在的行。我想用用户名“Foo”锁定不存在的行,这样我现在可以检查它是否存在于数据库中,如果它还不存在,就可以将它插入数据库中,而不会出现任何中断。

我知道使用< code>LOCK IN SHARE MODE和< code>FOR UPDATE是存在的,但是据我所知,那只对已经存在的行有效。我不知道在这种情况下该怎么办。

共有3个答案

柴嘉禧
2023-03-14

锁定不存在的记录在MySQL中不起作用。有几个关于它的错误报告:

    < li >选择...当表为空时,FOR UPDATE不执行排他锁 < li >添加谓词锁定,以避免由于锁定不存在的行而导致死锁

一种解决方法是使用互斥锁表,在插入新记录之前,现有记录将被锁定。例如,有两个表:卖家和产品。卖家有许多产品,但不应该有任何重复的产品。在这种情况下,卖家表可以用作互斥锁表。在插入新产品之前,将在卖家的记录上创建一个锁。通过这个额外的查询,可以保证在任何给定时间只有一个线程可以执行该操作。没有重复。没有死锁。

束飞捷
2023-03-14

如果用户名上有索引(应该是这种情况,如果没有,添加一个,最好是UNIQUE),那么发出一个SELECT * FROM user_table WHERE username = 'foo' FOR UPDATE;将阻止任何并发事务创建此用户(以及在非唯一索引的情况下,“上一个”和“下一个”可能的值)。

如果没有找到合适的索引(以满足WHere条件),则不可能进行有效的记录锁定,整个表将被锁定*。

这个锁将一直保持到发出< code>SELECT的事务结束...用于更新。

在这些手册页中可以找到一些关于这个主题的非常有趣的信息。

*我说高效,因为实际上记录锁实际上是对索引记录的锁定。当没有找到合适的索引时,只能使用默认的聚集索引,它将被完全锁定。

穆理
2023-03-14

虽然上面的答案是正确的...FOR UPDATE将防止并发会话/事务插入相同的记录,这并不完全正确。我目前正与同样的问题作斗争,并得出结论,选择...在这种情况下,强制更新几乎没有用,原因如下:

并发事务/会话也可以对相同的记录/索引值执行SELECT… FORUPDATE,MySQL会很乐意立即(非阻塞)接受,并且不会抛出错误。当然,一旦另一个会话完成了这一操作,您的会话也无法再插入记录。您和其他会话/事务都无法获得有关情况的任何信息,并且认为他们可以html" target="_blank">安全地插入记录,直到他们真正尝试这样做。尝试插入要么会导致死锁,要么会导致重复的密钥错误,具体取决于具体情况。

换句话说,SELECT… FORUPDATE阻止其他会话插入相应的记录,但是即使您执行SELECT… FORUPDATE并且找不到相应的记录,您也可能无法实际插入该记录。恕我直言,这使得“先查询,后插入”方法无用。

问题的原因是MySQL没有提供任何方法来真正锁定不存在的记录。两个并发的会话/事务可以同时锁定不存在的记录“进行更新”,这实际上是不可能的,并且会使开发变得更加困难。

解决这个问题的唯一方法似乎是使用信号量表,或者在插入时锁定整个表。有关锁定整个表或使用信号量表的更多信息,请参考MySQL文档。

只是我的2美分...

 类似资料:
  • 如何保证我可以搜索我的数据库中是否存在用户名,然后将该用户名作为新行插入数据库,而不会在和语句之间进行任何拦截? 几乎就像我锁定了一个不存在的行。我想用用户名“Foo”锁定不存在的行,这样我现在可以检查它是否存在于数据库中,如果它还不存在,就可以将它插入数据库中,而不会出现任何中断。 我知道使用< code>LOCK IN SHARE MODE和< code>FOR UPDATE是存在的,但是据我

  • 我有一个数据库(postgresql)与表Cdr。每个月都会在数据库中创建一个新表,该表具有与Table Cdr相同的模式,名为Cdr__(例如。Cdr_2016_04)。 我试图使用Jooq查询数据库,基于提供的日期。麻烦的是: 不起作用,因为它表明 组织。约克。例外DataAccessException:。。。来自cdr_2017_01,其中“公共”、“cdr”、“field1”和“公共”、“

  • 问题内容: 我正在尝试创建表(如果尚不存在)。我目前正在检查它是否首先存在,并且该查询是否不返回任何内容,然后插入。有没有一种方法可以只检查同一条语句,因此我不必将其分解为单独的查询? 这就是我目前所拥有的。 这是我要的东西。 问题是,您不能在语句中添加一个。 问题答案: 是的,Oracle没有该功能真是可惜。我敢肯定会有一天。在此之前,如果您想编写一个PL / SQL包装器,为什么不那样做:

  • 主要内容:1.磁盘or内存,2.数据页,3.用户记录,4.最大和最小记录,5.页目录,6.文件头部和尾部,7.页头部,8.总结innodb底层是如何存储数据的 1.磁盘or内存 1.1 磁盘 数据对系统来说是非常重要的东西,比如:用户的身份证、手机号、银行号、会员过期时间、积分等等。一旦丢失,会对用户造成很大的影响。 把数据存在磁盘上。 但是IO请求是比较耗时的操作,如果频繁的进行IO请求势必会影响数据库的性能。 1.2 内存 内存可以存储一些用户数据,但无法存储所有的用户数据,因为如果数据量太

  • 问题内容: 我有两个innodb表: 文章 票数 将新记录插入表中时,我想通过计算所有投票的总和来更新表中的字段。 如果SUM()计算本身非常繁琐(表有700K条记录),则哪种方法更有效。 1.创建触发器 2.在我的应用程序中使用两个查询 第一种方法看起来更干净,但是 在整个SELECT查询运行期间,表是否将被锁定? 问题答案: 关于并发问题,您有一种 “简便”的 方法来防止第二种方法中的任何并发

  • 本文向大家介绍详解MySQL(InnoDB)是如何处理死锁的,包括了详解MySQL(InnoDB)是如何处理死锁的的使用技巧和注意事项,需要的朋友参考一下 一、什么是死锁 官方定义如下:两个事务都持有对方需要的锁,并且在等待对方释放,并且双方都不会释放自己的锁。 这个就好比你有一个人质,对方有一个人质,你们俩去谈判说换人。你让对面放人,对面让你放人。 二、为什么会形成死锁 看到这里,也许你会有这样