Ну ... Ха. В течение многих лет никто не упоминал одну тонкую вещь.
Несмотря на то 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
, что уже заботится о предметной проблеме, и это хорошо.