Ну ... Ха. В течение многих лет никто не упоминал одну тонкую вещь.
Несмотря на то DROP TABLE IF EXISTS `bla`; CREATE TABLE `bla` ( ... );, что это кажется разумным, это приводит к ситуации, когда старая таблица уже исчезла, а новая еще не создана: некоторые клиенты могут попытаться получить доступ к предметной таблице прямо сейчас.
Лучше создать новую таблицу и заменить ее старой (содержимое таблицы теряется):
CREATE TABLE `bla__new` (id int); /* if not ok: terminate, report error */
RENAME TABLE `bla__new` to `bla`; /* if ok: terminate, report success */
RENAME TABLE `bla` to `bla__old`, `bla__new` to `bla`;
DROP TABLE IF EXISTS `bla__old`;
- Вы должны проверить результат
CREATE ...и не продолжать в случае ошибки , потому что сбой означает, что другой поток не завершил тот же сценарий: либо потому, что он потерпел крах в середине, либо просто еще не завершил - это хорошая идея осматривать вещи самостоятельно.
- Затем вы должны сначала проверить результат
RENAME ...и не продолжать в случае успеха : вся операция успешно завершена; Более того, выполнение next RENAME ...может (и будет) быть небезопасным, если другой поток уже запустил ту же последовательность (лучше охватить этот случай, чем не закрывать, см. примечание по блокировке ниже).
- Второй
RENAME ...атомарно заменяет определение таблицы,
подробности см. В руководстве MySQL .
- Наконец,
DROP ...просто убирает старую таблицу, очевидно.
Обтекание всех операторов чем-то вроде SELECT GET_LOCK('__upgrade', -1); ... DO RELEASE_LOCK('__upgrade');позволяет просто последовательно вызывать все операторы без проверки ошибок, но я не думаю, что это хорошая идея: повышается сложность, а функции блокировки в MySQL не безопасны для репликации на основе операторов.
Если данные таблицы должны выжить при обновлении определения таблицы ... В общем случае гораздо сложнее сравнить сравнения определений таблицы, чтобы найти различия и создать правильное ALTER ...утверждение, что не всегда возможно автоматически, например, при переименовании столбцов.
Примечание 1:
Вы можете иметь дело с представлениями, используя тот же подход, в этом случае CREATE/DROP TABLEпросто трансформируется в CREATE/DROP VIEWто время как RENAME TABLEостается неизменным. На самом деле вы можете даже превратить стол в вид и наоборот.
CREATE VIEW `foo__new` as ...; /* if not ok: terminate, report error */
RENAME TABLE `foo__new` to `foo`; /* if ok: terminate, report success */
RENAME TABLE `foo` to `foo__old`, `foo__new` to `foo`;
DROP VIEW IF EXISTS `foo__old`;
Примечание 2:
пользователи MariaDB должны быть довольны CREATE OR REPLACE TABLE/VIEW, что уже заботится о предметной проблеме, и это хорошо.