我试图将一个表复制到另一个表“原子地”。基本上我想定期更新一个表,这样如果另一个进程正在更新表,那么从表中读取的进程将不会得到不完整的结果。
为了提供一些背景信息,我想要一个充当游戏排行榜的桌子。该排行榜将通过单独的流程每隔几分钟更新一次。我的想法如下:
表格SCORES包含可在公众查看的排行榜,当用户查看排行榜时,该排行榜将被读取。此表每隔几分钟更新一次。更新排行榜的过程将创建包含新排行榜的SCORES_TEMP表。创建该表后,我想将其所有内容“原子地”复制到SCORES。我想我想做的是:
TRUNCATE TABLE SCORES;
INSERT INTO SCORES SELECT * FROM SCORES_TEMP;
我想替换SCORES中的所有内容。我不需要维护主键或自动增量值。我只是想从SCORES_TEMP中获取所有数据。但我知道,如果有人在完成这两个陈述之前查看了分数,那么排行榜将是空白的。我怎样才能原子地做到这一点,以至于它永远不会显示空白或不完整的数据?谢谢!
答案 0 :(得分:11)
RENAME TABLE old_table TO backup_table, new_table TO old_table;
它是原子的,适用于所有存储引擎,不必重建索引。
答案 1 :(得分:2)
在MySQL中,由于the behavior of TRUNCATE,我认为你需要:
BEGIN TRANSACTION;
DELETE FROM SCORES;
INSERT INTO SCORES SELECT * FROM SCORES_TEMP;
COMMIT TRANSACTION;
我不确定是否有办法让有效的DDL操作事务安全。
答案 2 :(得分:2)
您可以使用交易(InnoDB
),
BEGIN TRANSACTION;
DELETE FROM SCORES;
INSERT INTO SCORES SELECT * FROM SCORES_TEMP;
COMMIT;
或LOCK TABLES
(适用于MyISAM
):
LOCK TABLES;
DELETE FROM SCORES;
INSERT INTO SCORES SELECT * FROM SCORES_TEMP;
UNLOCK TABLES;
答案 3 :(得分:0)
我不知道热门的MySQL处理事务,但在T-SQL中你可以编写
BEGIN TRAN
DELETE FROM SCORES
INSERT INTO SCORES SELECT * FROM SCORES_TEMP
COMMIT TRAN
这样你的操作将是“原子的”,但不是瞬间的。