Мне нужна идея от вас, чтобы решить мою маленькую проблему здесь.У меня есть таблица, которая состоит из нескольких заданий с идентификатором, TIMESTAMP, STATE и некоторых других значений, определяющих, что это за задание на самом деле.Мне нужно найти идентификатор с наименьшим TIMESTAMP и где STATE = 1 и STATE необходимо установить на 2 в той же самой атомарной операции.
Это был бы способ сделать это, если действительно есть только одинклиент подключился к базе данных: сначала выберите идентификатор с наименьшим значением TIMESTAMP.
SELECT * FROM SW_ASYNC_JOBS WHERE STATE = 1 ORDER BY TIMESTAMP FETCH FIRST 1 ROW ONLY
Мы сохраняем идентификатор в переменной, скажем JOB_ID, затем устанавливаем его STATE равным 2:
UPDATE SW_ASYNC_JOBS SET STATE = 2 WHERE JOB_ID = :JOB_ID
Теперь клиент имеет все необходимые ему данные, устанавливает состояние «в процессе» и начинает работать над заданием.
Конечно, в действительности между этими двумя операциями будет другой клиент, который делает то же самоеи условия гонки обязательно произойдут.Оба клиента могут работать на одной и той же работе, которая является фатальной.
Я искал в Интернете и нашел операторы SELECT FOR UPDATE и WHERE CURRENT OF, но, похоже, нет способа также извлечь все столбцыработа.Я начал примерно так:
DECLARE
CURSOR FRESH_JOB IS
SELECT * FROM SW_ASYNC_JOBS WHERE STATE = 1 ORDER BY TIMESTAMP FETCH FIRST 1 ROW ONLY
FOR UPDATE;
BEGIN
FOR JOB IN FRESH_JOB LOOP
UPDATE SW_ASYNC_JOBS SET STATE = 2 WHERE CURRENT OF FRESH_JOB;
END LOOP;
END;
Но почему-то я получаю ошибку ORA-02014: cannot select FOR UPDATE from view
, что странно, потому что таблица SW_ASYNC_JOBS - это простая таблица с первичным ключом в двух столбцах.
Как лучше всего решить эту проблему?Стоит ли блокировать всю таблицу, чтобы получить самую старую работу и изменить ее состояние?
Для полноты этой таблицы я говорю:
CREATE TABLE SW_ASYNC_JOBS (
"MASTER_JOB_ID" NUMBER(22, 0) NOT NULL,
"JOB_ID" NUMBER(22, 0) NOT NULL,
"USER_ID" VARCHAR2(64) NOT NULL,
"UID" VARCHAR2(64) NOT NULL,
"VIEW" VARCHAR2(64) NOT NULL,
"JSON" VARCHAR2(2000) NOT NULL,
"TIMESTAMP" TIMESTAMP NOT NULL,
"STATE" NUMBER(2, 0) NOT NULL,
CONSTRAINT "SW_ASYNC_PRIMARY" PRIMARY KEY ("MASTER_JOB_ID", "JOB_ID")
)
Существуют другие клиенты, которые получают свежую последовательностьчисла из одной последовательности, чтобы добавить новые строки в эту таблицу.Сначала извлекается MASTER_JOB_ID, затем для каждого «подчиненного задания» используется другой свежий порядковый номер.Таким образом, в принципе ни одно число в пределах MASTER_JOB_ID
и JOB_ID
не может встречаться дважды.MASTER_JOB_ID
предназначен только для объединения нескольких «подчиненных заданий» и для отображения их группы состояний.
Клиент - это скрипт Python, использующий пакет cx_Oracle
в версии 12.1.0.2.0.