假设我有一个表MYTABLE
有两列
SERIALNUMBER, USERNAME
(其中SERIALNUMBER
是独一无二的)
多个连接可能会尝试使用相同的USERNAME
更新SERIALNUMBER
(假设为1)。
所以我发出查询:
SELECT USERNAME FROM MYTABLE WHERE SERIALNUMBER = 1 FOR UPDATE
如果此查询返回行(表示记录已经存在),我将发布更新
UPDATE MYTABLE SET USERNAME= <different name by each connection> WHERE SERIALNUMBER = 1
否则(记录尚不存在)我发出插入
INSERT INTO MYTABLE (SERIALNUMBER, USERNAME) VALUES ( 1, <different name by each connection>)
最后我发出
COMMIT
预期行为:
在查询中持有相同SERIALNUMBER
的连接应在SELECT.. FOR UPDATE
语句处等待。
如果记录已存在,则每个连接应逐个更新SERIALNUMBER
如果记录不存在,则第一次连接被授予SERIALNUMBER
保持锁定(因为SERIALNUMBER
尚不存在,如果没有错误,则为空位锁定){{1}新记录和后续连接,因为他们可以访问锁定应该找到记录已经存在。所以他们应INSERT
现有记录。
实际行为:
如果记录已存在,则按预期工作,每个连接更新记录及其UPDATE
如果记录尚不存在,则所有连接会同时继续尝试USERNAME
新记录。其中,一个成功,剩下的就是例外。不同隔离级别的例外情况有所不同。
对于INSERT
(这是InnoDB的默认值),它是:
MySQL错误代码:1213,SQLState:40001,#ERR:找到死锁时 试图锁定;尝试重新启动交易
对于REPEATABLE READ
,它是:
MySQL错误代码:1062,SQLState:23000,#ERR:重复条目“1” 关键'SERIALNUMBER'
问题陈述:
我想知道如何防止连接同时尝试为相同的字段值创建新记录(同时我希望只要字段值不同就允许并发记录创建)