Я пытаюсь написать среду экспериментов, в которой пользователь может запланировать некоторые эксперименты на основе идентификаторов местоположения и времени .
моя схема таблицы выглядит следующим образом:
TABLE experiment (
id INT NOT NULL PRIMARY KEY,
name varchar(20) NOT NULL,
locationIds varchar[] NOT NULL,
timeStart timestamp NOT NULL,
timeEnd timestamp NOT NULL,
createdAt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
updatedAt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
)
есть операции вставки, которые должны быть выполнены с условием, что местоположение и время не должны перекрываться. Я хотел знать, что можно сделать, чтобы избежать непоследовательности состояния данных, когда есть 2 одновременных вставки, занятых в тех случаях, когда местоположение ИЛИ время перекрывается,
В идеале я хочу, чтобы одна из вставок была успешной, но я в порядке Если оба сбоя и приложение должно повторить попытку.
Немного сблизился Я попытался подумать:
Подход:
APPROACH-1
- Имеет столбец enable , в котором указывается, является ли определенная запись действительной ИЛИ нет.
Я вставляю запись расписания эксперимента с enable = FALSE
Затем я проверяю, есть ли какая-либо другая запись, которая включена и перекрывается с текущей вставкой.
IF есть такая запись, тогда я ничего не делаю и этот эксперимент не запланирован. Остальное Я обновляю запись на enable = TRUE .
Проблема: если одновременно происходит конфликтующая вставка, оба получат enable = TRUE когда оба очистили шаг 3.
Я подумал, что если я позволю уровню изоляции транзакций быть незафиксированным для чтения, тогда я не смогу дифференцировать те, которые находятся в процессе а те, которые уже enable = TRUE
Тогда я подумал: если я отмечу enable как enum [IN_PROGRESS, ENABLED, DISABLED], то подход будет выглядеть следующим образом.
APPROACH-2
Имеет столбец enable , который сообщает, является ли определенная запись [IN_PROGRESS, ENABLED, DISABLED]
Я вставляю запись расписания эксперимента с enable = IN_PROGRESS
Затем я проверяю, есть ли какая-либо другая запись, которая enable = ENABLED ИЛИ enable = IN_PROGRESS и перекрывается с текущей вставкой.
* 108 4 * ЕСЛИ есть такая запись, тогда я обновляю enable = DISABLED , и этот эксперимент не запланирован. Иное Я обновляю запись до enable = ENABLED .
Проблема: если есть конфликтующая вставка одновременно, оба получат enable = DISABLED , когда оба очищают шаг-3 и получают такую перекрывающуюся запись.
Если уровень изоляции транзакции равен READ-COMMITTED , тогда это будет работать только ЕСЛИ каждый шаг это транзакция, а скорее весь процесс как одна транзакция. Если уровень изоляции транзакции равен READ-UNCOMMITTED , то это может быть принято за одну транзакцию, а состояние DISABLED также может быть принято за шаг ROLLBACK.
APPROACH-3
Используя решение на основе триггера, поскольку я использую POSTGRES, я могу добавить триггер для каждой операции вставки, опубликовать вставку, где я проверяю такую перекрывающуюся запись, если ее нет, затем я обновляю строка должна иметь enable = TRUE
CREATE OR REPLACE FUNCTION enable_if_unique()
RETURNS TRIGGER AS $$
BEGIN
IF (TG_OP = 'INSERT') THEN
UPDATE experiment
SET NEW.enable=true
WHERE (SELECT count(1)
FROM experiment
WHERE enable= true AND location_Ids && OLD.location_ids AND (OLD.timeStart, OLD.timeEnd) OVERLAPS (timeStart, timeEnd)
) = 0;
RETURN NEW;
END IF;
END;
$$ LANGUAGE 'plpgsql';
CREATE TRIGGER enable_if_unique_trigger BEFORE INSERT ON experiment FOR EACH ROW EXECUTE PROCEDURE enable_if_unique();
Я не уверен в подходе 3, потому что я чувствую, что для каждой операции вставки требуется, чтобы триггер действовал последовательно, чтобы один Эксперимента фактически включен, в то время как остальные перекрывающиеся из них отключены.
APPROACH-4
Из онлайн-поиска другого возможного решения я вижу вставки, задействованные с помощью Выбрать Оператор и предложение WHERE, помогающие добавить требуемое условие.
INSERT INTO experiment(id, name, locationIds, timeStart, timeEnd)
SELECT 1, 'exp-1', ARRAY[123,234,345], '2020-03-13 12:00:00'
WHERE (
SELECT count(1)
FROM EXPERIMENT
WHERE enable= true
AND
location_Ids && OLD.location_ids
AND
(OLD.timeStart, OLD.timeEnd) OVERLAPS (timeStart, timeEnd)
) = 0;
Я чувствую, что проблема согласованности все еще существует, поскольку обе параллельные операции не смогут читать каждый в операторе SELECT, проверяя ограничение.
Конечный ПОДХОД: APPROACH-2
Мне нравится знать следующее:
Какой наилучший подход с точки зрения масштабируемости и высокой пропускной способности?
Какой подход фактически обеспечивает поддержание согласованности данных?
Любой другой подход, который я мог бы здесь использовать и пропустить !!!
Новичок ie К POSTGRES, ПРИМЕРИТ ПРИМЕР ИЛИ ССЫЛКИ