У меня есть несколько таблиц для разных типов объектов. Однако идентификатор каждого объекта должен быть уникальным не только среди объектов одного типа, но и среди всех объектов разных типов. Другими словами, идентификатор должен быть уникальным в разных таблицах. Чтобы реализовать эту концепцию, я создал специальную таблицу со счетчиком с одним значением и изменил запросы INSERT, чтобы использовать ее. Теперь это выглядит так:
CREATE TABLE next_id (id INT NOT NULL); -- Table-counter
INSERT INTO next_id VALUES (1); -- The only value that points to the id for the next object
CREATE TABLE object1 ( -- One of object kinds
id INT NOT NULL PRIMARY KEY,
mass INT NOT NULL -- ... Another one specialized for object1 fields
);
CREATE TABLE object2 ( -- Other object kind
id INT NOT NULL PRIMARY KEY,
angles INT NOT NULL -- ... Another one specialized for object2 fields
);
INSERT INTO object1 (id, mass) VALUES ( -- Inserting object1
(
SELECT id -- Setting it's id by getting it from the counter
FROM next_id
), 5);
UPDATE next_id SET id=id+1; -- Changing the counter so that the next object has a different id
INSERT INTO object2 (id, angles) VALUES ( -- The same thing, but for other object kind
(
SELECT id
FROM next_id
), 3);
UPDATE next_id SET id=id+1;
Но это выглядит очень странно, и я беспокоюсь, что оператор UPDATE может быть выполнен позже планировщиком, что приведет к коллизиям идентификаторов и другим проблемам. Можно ли это изменить, чтобы идентификатор вел себя как AUTO_INCREMENT? Я имею в виду автоматическую установку идентификатора, например:
INSERT INTO object1 (mass) VALUES (5); -- Id is set automatically
Почему бы не использовать Auto_INcrenet? см. скрипку
@nbk Это интересный способ сделать это, но при этом создается много ненужных строк с последовательностью всех идентификаторов, которые были созданы когда-либо.
вы можете добавить транзакцию на всех языках программирования, чтобы она не создавала лишних идентификаторов, поскольку вы запускаете ее только при вставках
@ShkiperDesna и это одновременно безопасно
Вы можете использовать Triggers
вот так
сначала нам нужно создать таблицу next_id
CREATE TABLE next_id (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
);
Инициализировать таблицу идентификаторов
INSERT INTO next_id VALUES (NULL);
Теперь создайте триггер для каждой таблицы.
object1
CREATE TRIGGER before_insert_object1
BEFORE INSERT ON object1
FOR EACH ROW
BEGIN
DECLARE new_id INT;
SET new_id = (SELECT id FROM next_id FOR UPDATE);
SET NEW.id = new_id;
UPDATE next_id SET id = id + 1;
END;
object2
CREATE TRIGGER before_insert_object2
BEFORE INSERT ON object2
FOR EACH ROW
BEGIN
DECLARE new_id INT;
SET new_id = (SELECT id FROM next_id FOR UPDATE);
SET NEW.id = new_id;
UPDATE next_id SET id = id + 1;
END;
Альтернативно вы можете использовать такие UUID
CREATE TABLE object1 (
id CHAR(36) NOT NULL PRIMARY KEY,
mass INT NOT NULL
);
CREATE TABLE object2 (
id CHAR(36) NOT NULL PRIMARY KEY,
angles INT NOT NULL
);
Вставка данных с использованием UUID
INSERT INTO object1 (id, mass) VALUES (UUID(), 5);
INSERT INTO object2 (id, angles) VALUES (UUID(), 3);
Вы должны INSERT в триггере, а не SELECT + UPDATE !!!
Где обновление? Есть ли проблемы с ответом?
@Akina Почему плохо использовать SELECT + UPDATE? Я попробовал это только сейчас, и никаких проблем не произошло.
@ShkiperDesna Вы не пробовали это в параллельной среде.
«... Меня беспокоит, что оператор UPDATE может быть выполнен планировщиком позже...» -- Нет. Запросы будут выполняться один за другим в указанном вами порядке. Если сценарий запускается в одном сеансе и нет одновременного выполнения этого сценария, все должно быть хорошо.