xLi*_*ite 17 mysql innodb locking rowlocking database-locking
我如何保证我可以搜索我的数据库中是否存在用户名,然后将该用户名作为新行插入数据库而不在SELECT和INSERT语句之间进行任何拦截?
几乎就像我锁定了一个不存在的行.我想用用户名"Foo"锁定不存在的行,这样我现在可以检查它是否存在于数据库中并将其插入到数据库中(如果它尚不存在而没有任何中断).
我知道使用LOCK IN SHARE MODE和FOR UPDATE存在,但据我所知,这只适用于已经存在的行.我不知道在这种情况下该怎么做.
Ran*_*eed 19
如果有索引username(应该是这种情况,如果没有,则添加一个,最好是UNIQUE一个),然后发出一个SELECT * FROM user_table WHERE username = 'foo' FOR UPDATE;将阻止任何并发事务创建此用户(以及"上一个"和"下一个")在非唯一索引的情况下可能的值).
如果找不到合适的索引(满足WHERE条件),则无法进行有效的记录锁定,整个表将被锁定*.
此锁定将一直持续到发布的事务结束SELECT ... FOR UPDATE.
有关此主题的一些非常有趣的信息可以在这些手册页中找到.
*我说效率很高,因为实际上记录锁实际上是对索引记录的锁定.如果找不到合适的索引,则只能使用默认的聚簇索引,并且它将被完全锁定.
Bin*_*rus 16
虽然上面的答案是正确的,因为SELECT ... FOR UPDATE将阻止并发会话/事务插入相同的记录,这不是完整的事实.我目前正在解决同样的问题,并得出结论,SELECT ... FOR UPDATE在这种情况下几乎无用,原因如下:
并发事务/会话也可以在相同的记录/索引值上执行SELECT ... FOR UPDATE,并且MySQL将很乐意立即接受(非阻塞)并且不会抛出错误.当然,只要其他会话完成,您的会话也不能再插入记录了.您和其他会话/交易也不会获得有关情况的任何信息,并认为他们可以安全地插入记录,直到他们真正尝试这样做.尝试插入然后导致死锁或重复键错误,具体取决于具体情况.
换句话说,SELECT ... FOR UPDATE阻止其他会话插入相应的记录,但即使你做了一个SELECT ... FOR UPDATE并且找不到相应的记录,很可能你实际上不能插入该记录.恕我直言,这使得"第一个查询,然后插入"方法无用.
问题的原因是MySQL没有提供任何方法来真正锁定不存在的记录.两个并发会话/事务可以同时锁定不存在的记录"FOR UPDATE",这实际上是不可能的,这使得开发变得更加困难.
解决这个问题的唯一方法似乎是使用信号量表或在插入时锁定整个表.有关锁定整个表或使用信号量表的更多参考,请参阅MySQL文档.
只差我2美分......
锁定不存在的记录在MySQL中不起作用.有几个关于它的错误报告:
一种解决方法是使用互斥表,在插入新记录之前将锁定现有记录.例如,有两个表:卖家和产品.卖家有很多产品,但不应该有任何重复的产品.在这种情况下,卖家表可以用作互斥表.在插入新产品之前,将在卖方记录上创建锁定.使用此附加查询,可以保证在任何给定时间只有一个线程可以执行操作.没有重复.没有死锁.
| 归档时间: |
|
| 查看次数: |
5262 次 |
| 最近记录: |