使用事务启动MySQL之前的值的多个更新语句

时间:2014-03-02 01:45:09

标签: php mysql sql transactions

我正在尝试在MySQL事务中运行多个更新语句,但我需要在每个语句中使用WHERE子句来引用事务开始之前存在的值。 (使用innoDB表。)

例如,我有以下航班表(简化,显然):

flight  aircraft     dep_time
1       1            05:00
2       1            06:00
3       1            07:00

4       2            05:00
5       2            06:00
6       2            07:00

我需要做的是在06:00或更晚的飞机1上交换航班,飞机2的航班在06:00或更晚离开。我目前这样做是通过为每个航班分配一架中间飞机,然后用这架中间飞机更新飞机到所需的飞机。例如:

UPDATE flights SET aircraft = 1001 WHERE aircraft = 1 AND dep_time >= 06:00
UPDATE flights SET aircraft = 1002 WHERE aircraft = 2 AND dep_time >= 06:00
UPDATE flights SET aircraft = 2 WHERE aircraft = 1001
UPDATE flights SET aircraft = 1 WHERE aircraft = 1002

似乎我可以通过使用事务来避免两个额外的更新语句。另外,如果数据库中实际存在飞机1001,我现在使用的方法会引起严重问题(此时我只是使用非常大的数字来确保不会发生这种情况)......我想避免。我的意图是做这样的事情:

START TRANSACTION();
UPDATE flights SET aircraft = 2 WHERE aircraft = 1 AND dep_time >= 06:00
UPDATE flights SET aircraft = 1 WHERE aircraft = 2 AND dep_time >= 06:00
COMMIT();

据我所知,第二个更新语句将看到第一个语句中更新的值,这将使一切变得混乱。有没有办法让两个UPDATE语句都使用事务启动时存在的值?如果没有,有没有人有更好的建议如何处理这个?

我希望的结果是:

flight  aircraft     dep_time
1       1            05:00
2       2            06:00
3       2            07:00

4       2            05:00
5       1            06:00
6       1            07:00

谢谢!如果不清楚,我道歉......

2 个答案:

答案 0 :(得分:0)

您需要在表中添加唯一列(通常它将具有名称id并且是无符号的大型int auto_increment类型)

然后,只要每行都有唯一的ID,您就可以根据需要交换行。

答案 1 :(得分:0)

这根本不是关于交易的,而是关于使用UPDATE来交换价值(无论是否在单个交易中)。交易不会像你的问题暗示的那样“保存交易开始时存在的数据”:你似乎误解了它们的用途。您可以COMMITROLLBACK正在进行的事务,但您不能编写明确引用当前事务数据库与事务前数据库数据的查询。

如果您需要在给定时间点“保存”数据,则可以将其复制到临时表,或者复制到当前表中为此(临时存储)目的而创建的其他列。

但是,更简单的解决方案是:如果您可以将整个事物编写为单个更新语句,那么您将不会遇到任何问题,因为每行只会被处理一次单UPDATE,例如:

UPDATE flights SET aircraft = IF(aircraft=1,2,1) WHERE (aircraft = 1 OR aircraft = 2) AND dep_time >= 06:00
在这种特殊情况下,

应解决您的问题。

(也就是说,请注意,如果您要更新主键或唯一键,行仍然会逐个更新,这可能会导致重复键错误,即使 final 更新的结果将没有任何。所以在这种情况下,您可能必须使用ORDER BY仔细订购更新,否则您可能必须临时插入虚拟值并使用多个UPDATE语句,你现在的方式。)