我有 3 个表:
Counters: ID, ItemCatalogID, CurrentCounter
Item: ID, ItemCatalogID, Name, Description, OtherValue
ItemCatalog: ID, Name, Description
Counters 表包含项目目录的 CurrentCounter,当我插入一行时,我必须查询 DB,获取相应目录的当前计数器,然后将此值更新为 1,并将此值用于 OtherValue 字段。
例如:
update Counters set CurrentCounter = CurrentCounter + 1 where ItemCatalogID = 100;
select CurrentCounter into v from Counters where ItemCatalogID = 100;
insert into Item(ItemCatalogID, Name, Description, OtherValue) values (100, 'MyItem', 'Short Description', v);
但我想知道竞争条件会发生吗?如何改进我的解决方案?
最佳答案
是的,您的情况可能会引发竞争条件。
您是否需要这些计数器?您可以轻松地将它们替换为适当的查询:
SELECT COUNT(*) FROM ItemCatalog WHERE ID=100;
SELECT COUNT(*) FROM Item WHERE ID=100;
对于连续的字段内容,建议使用 AUTO_INCREMENT
列。但这似乎不适用于您的情况。
但是,您仍然可以使用上面的 COUNT(*)
方法:
insert into Item(ItemCatalogID, Name, Description, OtherValue) values (100, 'MyItem', 'Short Description', (select count(*) from Item where ID=100));
可能您必须为您的表的其中一个事件起别名:
insert into Item(ItemCatalogID, Name, Description, OtherValue) values (100, 'MyItem', 'Short Description', (select count(*) from Item AS I where ID=100))
这一步执行,您不必担心竞争条件。
如果由于某种原因您无法更改它,还有另一种解决方案:使用表锁定。
在你的语句前加上
LOCK TABLES Counters WRITE, Item WRITE
并为它们加上后缀
UNLOCK TABLES
为了拥有对它们的独占写入权限。
关于mysql - 插入行时的竞争条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21201000/