Вот выдержка из моей текущей базы данных (для облегчения понимания изменил имена таблиц):
Pet(ownerFK, id, name, age)
Owner(id, name)
Где id
- это всегда суррогатный ключ, созданный с помощью auto_increment
.
Я хочу, чтобы суррогатный ключ Pet.id
был "ограничен" Pet.ownerFK
или, другими словами, в качестве минимального ключа был бы составной ключ [ownerFk, id]
. Я хочу, чтобы таблица вела себя так:
INSERT Pet(1, ?, "Garfield", 8);
INSERT Pet(1, ?, "Pluto", 12);
INSERT Pet(2, ?, "Mortimer", 1);
SELECT * FROM Pet;
RESULT:
Pet(1, 1, "Garfield", 8)
Pet(1, 2, "Pluto", 12)
Pet(2, 1, "Mortimer", 1)
В настоящее время я использую эту функцию MyISAM , где «вы можете указать AUTO_INCREMENT
для дополнительного столбца в индексе из нескольких столбцов. В этом случае сгенерированное значение для столбец AUTO_INCREMENT
рассчитывается как MAX(auto_increment_column) + 1 WHERE prefix=given-prefix
. Это полезно, когда вы хотите поместить данные в упорядоченные группы. "
Однако из-за различных (и, возможно, очевидных) причин я хочу переключиться с MyISAM на InnoDB, так как мне нужны транзакции в некоторых местах.
Есть ли способ, как добиться этого эффекта с помощью InnoDB ?
Я нашел несколько сообщений по этому вопросу, многие из них предложили заблокировать запись таблицы перед вставкой. Я не очень знаком с этим, но не будет ли блокировка таблицы записи немного капитальным ремонтом для этого? Я скорее думал о том, чтобы иметь безопасные от записи транзакции (чего я никогда раньше не делал), если это возможно - иметь Owner.current_pet_counter
в качестве вспомогательного поля.
Таким образом, другим приемлемым решением будет ...
На самом деле мне не нужен идентификатор "scoped", чтобы быть частью настоящего ключа. Мой фактический дизайн базы данных использует отдельную таблицу «постоянных ссылок», которая использует эту «функцию». В настоящее время я использую его в качестве обходного пути для отсутствующих транзакций. Я подумал о следующей альтернативе:
Pet(id, ownerFK, scopedId, name, age), KEY(id), UNIQUE(ownerFK, scopedId)
Owner(id, name, current_pet_counter)
START TRANSACTION WITH CONSISTENT SNAPSHOT;
SELECT @new=current_pet_counter FROM Owner WHERE id = :owner_id;
INSERT Pet(?, :owner_id, @new, "Pluto", 21);
UPDATE Owners SET current_pet_counter = @new + 1 WHERE id = :owner_id;
COMMIT;
Я еще не работал с транзакциями / транзакциями в MySQL, поэтому я не знаю, будут ли серьезные проблемы с этим.
Примечание: Я не хочу повторно использовать id
s, которые были даны домашнему животному один раз. Вот почему я не использую MAX()
. Есть ли у этого решения какие-либо предостережения?