Поддержка внешних ключей и транзакций — это основные отличия InnoDB от других типов таблиц MySQL. Эти механизмы служат для защиты целостности данных.
Прежде чем приступить к работе с типом таблиц InnoDB, стоит проверить, поддерживается ли он в
Вашем MySQL. В PhpMyAdmin (PMA)
переходим на вкладку "Сервер" -> раздел "Переменные и настройки сервера" и находим переменную "have innodb".
Если "have innodb" содержит значение DISABLED, поддержка InnoDB отключена. Нужно изменить настройки конфигурационного файла – my.cnf (обычно лежит в корне папки mysql).
Если в Windows не получается открыть этот файл, можно воспользоваться программой Far. Находим конфигурационный файл,
открываем его (клавишей F4), находим следующую строку: "skip-innodb",
и проверяем чтобы она была закомментирована. Сохраняем конфигурационный файл (F2) и перезагружаем апач.
Указать тип можно при создании новой таблице, например:
Можно задать и позже через PMA: вкладка "Операции" -> раздел "Тип таблицы", либо командой:
Внешние ключи
Чтобы проще было понять, какие возможности предоставляет механизм внешних ключей, рассмотрим пример. Будем работать с тремя таблицами: пользователей, товаров и заказов. Каждая из таблиц имеет уникальные ключи: userid, prodid и ordid соответственно.
Схема взаимодействия таблиц:
Состав первых двух таблиц понятен. Рассмотрим подробнее таблицу заказов. Каждая запись о заказе содержит в себе информацию о товаре (prodid) и пользователе (userid). Нам важно, чтобы эти значения были действительными. Предположим, пользователь заказал товар, а администратор его удалил, тогда запись о заказе стала "поломанной" (мы даже не узнаем, какой товар был заказан). Чтобы этого избежать, нужно задать правило, согласно которому, множество значений поля userid в таблице заказов (дочерней таблице) не будет превышать множества значений ключа userid в таблице пользователей (родительской таблице). Это правило реализует механизм внешних ключей.
Запросы на создание таблиц:
Строка
задаёт внешний ключ и буквально означает следующее: назначить полю userid из таблицы orders внешний ключ на поле userid из таблицы users.
Теперь мы не сможем создать запись в таблице orders со значениям полей userid или prodid, которых нет в родительских таблицах. А для операций редактирования и удаления мы можем задать особые правила:
CASCADE – означает распространение действий родительской таблицы на дочерние: то есть, если значение ключа в родительской таблице изменится, то оно автоматически (!без специальных запросов) изменится и в дочерних таблицах.
RESTRICT — означает, что нельзя редактировать значение ключа или удалять строки из родительской таблицы, пока есть соответвующие внешние ключи в дочерних таблицах (это правило является правилом по умолчанию).
Заполним немного наши таблицы для эксперементов:
Итого: Гриша заказал кофту и джинсы, Мария маечку и Камилла также джинсы. Федос ничего не заказывал.
Эксперемент №1. Попробуем внести в таблицу orders запись с номером пользователя, отсутствующим в таблице users:
Если мы все правильно сделали, MySQL выдаст ошибку.
Если у Вас не выдаётся ошибка, то проверьте поддержку типа InnoDB Вашим MySQL.
Эксперемент №2. Изменим значение ключа в таблице пользователей с правилом ON UPDATE CASCADE и убедимся, что таблица заказов сама изменила значение соответствующего поля userid.
Эксперемент №3. ON DELETE CASCADE - эта опция означает каскадное удаление: то есть если будет удалена строка из родительсткой таблицы, то автоматически будут удалены строки с соответсвующим внешним ключом из дочерней таблицы. Для нашего случая это означает, что мы исключаем ситуацию покупки товара, которого нет в базе данных: если удалится товар, то и удалятся записи о заказе соответвующего товара. Например, удалим запись из таблицы товаров с ключом prodid=3. Поскольку внешний ключ prodid в таблице заказов использует правило ON DELETE CASCADE, это значит, что автоматически с записью из таблицы products, удалятся записи в таблице orders, в которых поле prodid=3.
Эксперемент №4. Попробуем обновить значение ключа в таблице товаров, на который ссылается внешний ключ prodid из таблицы orders с правилом ON UPDATE RESTRICT и убедимся, что MySQL выдаст нам ошибку о невозможности завершения этого запроса:
Ответ MySQL:
Эксперемент №5. Если мы попробуем удалить запись из таблице пользователей, значение ключа которого используется в таблице заказов (то есть мы хотим удалить товар, который есть в списках заказа пользователей), причём на внешний ключ которой наложено правило ON DELETE RESTRICT, MySQL выдаст нам ошибку.
Ответ MySQL:
Вывод: ----
Транзакции
Транзации также позволяют контроливать целостность данных, так как дают возможность выполнять пакет запросов и в случае ошибки на одном из эпатов, отменяют все предыдущие действия.
Приведу пример: чтобы создать аккаунт пользователя нам нужно:
Обычно нам потребовалось бы три запроса к БД, чтобы создать аккаунт. Предположим первые два запроса выполнились удачно, а при третьем запросе нарушилась связь с БД и он "провалился". Таким образом у нас создался "поломаный" аккаунт, без записи в таблице прав. Какие могут быть последствия, можно себе представить.
Чтобы избежать подобных ситуаций, тип InnoDB имеет возможность реализовывать транзации. Для нашего случая это значит, что если не выполнился один из запрос, предыдущие будут также отменены.
Попробуем выполнить следующий запрос:
Сначала удалится запись в таблице заказов с пользователем с порядковым номером 1, а затем MySQL выдаст ошибку, потому что в таблице заказов нет столбца с именем "userid1"
Попробуем заключить эти запросы в транзакцию:
MySQL по-прежднему выдал ошибку о некорректном названии столбца, вот только из таблицы заказов он не удалил заказы пользователя с порядковым номером 1.
(!) Хочу обратить внимание, что запросы отменятся только в случае ошибки, а не в случае, если количество
отработанных строк будет равно нулю.
Источник scabbiaza.net