Моя таблица 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, наконец, запускает два оператора insert:
Проблема возникает, когда новый запрос приходит с family_id, который существует в таблице. Это не должно быть разрешено, и я делаю запрос для поиска, существует ли family_id или нет. Если он существует, возникает исключение. Как я могу избежать этого запроса? При необходимости схема таблицы может быть изменена. Было бы хорошо, если бы он мог добавить что-то вроде "идентификатора запроса" или руководства, чтобы установить уникальность для каждого запроса?
Все данные должны быть в одной таблице.
Ниже пример таблицы с некоторыми данными
(из комментария) Я не могу создать вторую таблицу. Все должно храниться в одном столе.
Вы должны нормализовать свою схему и использовать две таблицы.
Семья и (я предполагаю) Личность. Затем вы можете использовать ограничение UNIQUE
для family_id
и добавить family_id как внешний ключ в таблицу Person.
Вам нужны две таблицы.
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"
);
PRIMARY KEY
- UNIQUE KEY
- KEY
.
Вы говорите, что вы не можете добавить вторую таблицу. Но почему? Вы упомянули о необходимости создания конкретного JSON? Не может ли это быть сделано просто через JOIN
из двух таблиц, если это необходимо?
Если вы не можете создать вторую таблицу для правильного моделирования ограничения, тогда вам придется прибегать к сериализации вставок:
LOCK TABLES new_table WRITE;
SELECT
чтобы проверить, существует ли идентификатор семейства в таблице.INSERT
свои новые данные.UNLOCK TABLES;
Необходимо заблокировать стол, потому что иначе у вас будет состояние гонки. Две сессии могут проверить, существует ли семейный идентификатор, и обнаруживают, что он не существует, а затем оба продолжают свой INSERT
. Если вы заблокируете таблицу, то один сеанс получит блокировку и выполнит ее работу, в то время как другой сеанс должен дождаться блокировки, и к моменту приобретения блокировки его проверка обнаружит, что идентификатор семейства был вставлен Первая сессия.
Этот метод обычно считается неудачным для параллелизма, который может ограничить вашу пропускную способность, если у вас много запросов. Но если у вас есть редкие запросы, влияние на пропускную способность будет минимальным.
Это обходной путь для проблемы с дизайном, но я решил, что могу опубликовать его. Вы можете создать такой запрос, как:
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
Затем проверьте количество затронутых строк, чтобы определить, было ли это успешным или нет.