从我的阅读中我相信SELECT FOR UPDATE将用于完成以下操作,但我读了类似于“行锁定不会停止读取”的注释,这让我觉得我错过了一些东西。原谅我的伪代码。
table 'first_names'
`name` `used`
mike 1
jeff null
mark null
我需要从这个表中获取一个名称,但绝对100%确保它以前从未使用过,并且不会被其他任何东西使用。 (一个假的例子,假设我们自动分配用户名 - 当有人在我们的网站上创建一个帐户时必须是唯一的)为了实现这一点,当我从这个表中获取/使用一个名字时,我们设置used = 1。
但问题当然是两个独立的进程select where used <> 1
如果进程#1在进程#2运行update used = 1
之前没有select where used <> 1
,则可以获得“jeff”。
在事务中SELECT FOR UPDATE是否解决了这个问题?我知道它会锁定行,以便另一个进程不能写到该行,但我们正在进行读取,选择。含义进程#1和进程#2同时运行select where null <> 1
,因此得到相同的行(jeff)。进程#1写入行update used = 1
,释放锁,现在进程#2也写入行....现在行jeff已被使用了两次。
答案 0 :(得分:1)
另一种方法是拥有日志/事务表。
NameUsed
----------
Mike
首先检查名称是否已被使用
select count(*) from log where nameused='jeff'
这会返回&#39; 0&#39;对于这两个进程,相对确定该名称是免费的两个进程运行:
Insert into log (NameUsed) values('jeff');
诀窍是NameUsed
是UNIQUE
列,您的DBMS只允许您的某个进程成功插入名称,其中一个将失败,并且必须是唯一的&#39;这比其他用户锁定更有帮助&#39;。
此方法可优化写入速度并最大限度地减少主表的锁定。
检查名称是否已被使用但速度稍慢,但使用正确的索引并不多。