【发布时间】:2012-08-10 16:25:26
【问题描述】:
我需要完成以下工作:
我需要在同一个表中插入两行,要么都插入,要么都不插入(原子插入两行)。
我使用 InnoDB 表上的事务来执行此操作,如下所示:
$db->beginTransaction();
# Using PDO prepared statments, execute the following queries:
INSERT INTO t1 set uid=42, foo=1
INSERT INTO t1 set uid=42, foo=2
$db->commit();
但是,如果表中没有列的值为“42”的行,我也只希望插入这些行。
所以我这样做:
$stmt = $db->prepare("SELECT id FROM t1 WHERE uid != ?");
$stmt->execute(array(42));
if($stmt->fetchColumn() < 0){
# There is no row with uid=42, so
# perform insertions here as per above.
INSERT INTO t1 set uid=42, foo=1
INSERT INTO t1 set uid=42, foo=2
}
但是这里存在竞争条件,因为 uid=42 的行可以在检查该行之后立即插入,并且在插入新行之前插入。
我应该如何解决这个问题?
我可以锁定表,然后在表锁内执行 InnoDB 事务吗?
我可以在事务内部进行选择以检查 uid=42 的现有行吗?那是没有竞争条件的吗?
【问题讨论】:
-
看看 REPLACE INTO .. 而不是 INSERT。但是,如果记录已存在,它将执行更新。
-
看看你的表模式会很有趣。听起来您要做的是强制执行唯一索引,而字段本身没有唯一索引。虽然我可以看到您正在尝试使用相同的 uid 插入多行,但这对我来说真的没有意义。看起来您的问题可能可以通过表规范化和使用唯一索引来解决。
-
我的想法是在提交之前和之后仔细检查 42。
-
我和@Mike Brant 在一起,您似乎正在尝试使用 PHP 代码强制执行 unique 数据库列约束。
-
为什么是 42?你意识到这不是真的生命、宇宙和一切的答案,对吧?