我需要更新包含另一个表(FK约束到oldsmalltable)的id的表(bigtable)的特定列,以指向另一个表上的id(FK约束到newsmalltable).基本上这就是我在做的事情:
DELIMITER //
CREATE PROCEDURE updatebigtable ()
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION, SQLWARNING ROLLBACK;
START TRANSACTION;
ALTER TABLE bigtable DROP FOREIGN KEY bigtable_ibfk_1,
MODIFY smalltable_id SMALLINT ;
UPDATE bigtable SET smalltable_id=CASE smalltable_id
WHEN 1 THEN 1592
WHEN 2 THEN 1593
WHEN 3 THEN 1602
...
ELSE 0
END;
ALTER TABLE bigtable ADD CONSTRAINT bigtable_ibfk_1
FOREIGN KEY(smalltable_id) REFERENCES newsmalltable(id);
COMMIT;
END//
DELIMITER ;
CALL updatebigtable();
DROP PROCEDURE updatebigtable;
我需要确保如果由于某种原因新的外键约束失败(例如,对于具有不同类型的列,错误将发生在最后一个alter table语句上),UPDATE和第一个ALTER TABLE也应该回滚,即他们应该保持原状.
根据MySQL documentation,通过使用START TRANSACTION,该事务禁用自动提交模式,这将不允许:
that as soon as you execute a statement that updates (modifies) a table, MySQL stores the update on disk to make it permanent.
我只发现这个问题与我的问题微不足道:
How can I use transactions in my MySQL stored procedure?
如果我提到的错误发生在事务中,之前的语句已经执行,更新“永久在磁盘上完成”……
我也试过放置SET autocommit = 0;在创建程序之前但行为仍然相同……我错过了什么吗?或者这是MySQL事务回滚的预期行为?
如果它有任何区别,我使用的是MySQL v.5.6.17.
最佳答案 ALTER TABLE语句总是导致隐式提交(
section 13.3.3 from MySQL docs,谢谢
wchiquito),这意味着即使它们在START TRANSACTION中; ……承诺;块,将在该块内完成的更改次数与提交的次数相同.
自(from problems with ALTER TABLE
)起,锁定表格也不是一个选项:
If you use
ALTER TABLE
on a transactional table or if you are using Windows,ALTER TABLE
unlocks the table if you had done aLOCK TABLE
on it. This is done because InnoDB and these operating systems cannot drop a table that is in use.
在执行alter和update语句时,唯一可以避免不需要的读/写操作的选项是模拟ALTER TABLE的所有步骤:
- Create a new table named A-xxx with the requested structural changes.
- Copy all rows from the original table to A-xxx.
- Rename the original table to B-xxx.
- Rename A-xxx to your original table name.
- Delete B-xxx.
这样,更新可以在新表中完成(在步骤2之后),并且bigtable不可用的唯一时间是在执行步骤3和4(重命名)时.