Добавление ограничений в базу данных MySQL, чтобы гарантировать уникальность - PullRequest
0 голосов
/ 03 июля 2018

Моя таблица SQL имеет следующий DDL

CREATE TABLE `new_table` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `family_id` int(11) NOT NULL,
  `name` varchar(45) NOT NULL,
  PRIMARY KEY (`id`)
  ) 

Я хочу держать фамилии в этой простой таблице. Для этого у меня есть микросервис, в котором звонящий отправляет через JSON семейные данные:

{
  "family_id" : 1,
  "names": ["name1", "name2"]
}

Идентификатор генерируется с помощью автоинкремента из MySQL.

Таким образом, вышеприведенный JSON, наконец, вызовет два оператора вставки:

  • вставить (family_id, name) значения (1, name1)
  • вставить (family_id, name) значения (1, name2)

Проблема возникает, когда приходит новый запрос с идентификатором family_id, который существует в таблице. Это не должно быть разрешено, и я делаю запрос для поиска, существует ли family_id или нет. Если оно существует, возникает исключение. Как я могу избежать этого запроса? Схема таблицы может быть изменена при необходимости. Было бы хорошо, если бы можно было добавить что-то вроде «идентификатора запроса» или руководства, чтобы установить уникальность для каждого запроса?

Все данные должны быть в одной таблице.

Ниже приведен пример таблицы с некоторыми данными

enter image description here

(из комментария) Я не могу создать вторую таблицу. Все должно храниться в одном столе.

Ответы [ 4 ]

0 голосов
/ 11 июля 2018

Это обходной путь для проблемы дизайна, но я подумал, что я мог бы также опубликовать его. Вы можете сгенерировать запрос, такой как следующий:

INSERT INTO `new_table` (`family_id`, `name`)
SELECT * FROM (
    SELECT 1, 'name1'
    UNION ALL
    SELECT 1, 'name2'
) x
LEFT JOIN `new_table` n ON n.family_id = 1
WHERE n.family_id IS NULL

Затем проверьте количество затронутых строк, чтобы определить, было ли оно успешным или нет.

0 голосов
/ 11 июля 2018

Вам нужно две таблицы.

CREATE TABLE Families (
    family_id MEDIUMINT UNSIGNED  AUTO_INCREMENT,
    ...
    PRIMARY KEY(family_id)
    );

CREATE TABLE FamilyNames (
    family_id MEDIUMINT UNSIGNED,   -- not auto-inc here
    name VARCHAR(66) NOT NULL,
    ...
    PRIMARY KEY(family_id, name)    -- note "composite"
    );

A PRIMARY KEY является UNIQUE KEY является KEY.

Вы говорите, что не можете добавить вторую таблицу. Но почему? Вы упоминаете о необходимости генерировать конкретный JSON? Разве это не может быть просто сделано через JOIN из двух таблиц, если необходимо?

0 голосов
/ 11 июля 2018

Если вы не можете создать вторую таблицу для правильного моделирования ограничения, вам придется прибегнуть к сериализации вставок:

  1. LOCK TABLES new_table WRITE;
  2. Используйте SELECT, чтобы проверить, существует ли в таблице идентификатор семьи.
  3. Если идентификатор семьи отсутствует, INSERT ваши новые данные.
  4. UNLOCK TABLES;

Необходимо заблокировать стол, потому что иначе у вас будет состояние гонки. Два сеанса могут проверить, существует ли идентификатор семейства, оба обнаружат, что его не существует, и затем оба продолжат работу со своим INSERT. Если вы заблокируете таблицу, то один сеанс получит блокировку и выполнит свою работу, в то время как другой сеанс должен ждать блокировки, и к тому времени, когда он получит блокировку, его проверка обнаружит, что идентификатор семейства был вставлен первый сеанс.

Этот метод обычно считается плохим для параллелизма, который может ограничить вашу пропускную способность, если у вас много запросов. Но если у вас есть нечастые запросы, влияние на пропускную способность будет минимальным.

0 голосов
/ 03 июля 2018

Вы должны нормализовать свою схему и использовать две таблицы.

Семья и (я полагаю) человек. Затем вы можете использовать ограничение UNIQUE для family_id и добавить family_id в качестве внешнего ключа в таблицу Person.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...