Выберите из таблицы в Oracle с несколькими сессиями - PullRequest
1 голос
/ 01 октября 2009

У меня есть несколько потоков, которые обрабатывают строки из одной и той же таблицы, которая фактически является очередью.

Я хочу, чтобы каждый ряд обрабатывался только одним потоком. Итак, я добавил столбец - «IsInProccess», и в операторе SELECT потоков я добавил «WHERE IsInProccess = 0». Кроме того, я использую «SELECT FOR UPDATE», поэтому после того, как поток получит строку из таблицы, никакой другой поток не получит ее, пока не поместит 1 в «IsInProccess».

Проблема в том, что у меня много потоков, и во многих случаях происходит следующий сценарий: Поток A выбирается с помощью «SELECT FOR UPDATE» из таблицы и получает номер строки. 1 . Перед изменением IsInProccess на 1 поток B выбирает таким же образом из таблицы и также получает строку № 1 . Oracle сохранить строку №. 1 в поток A сеанс и поток B не может изменить эту строку и вернуть ошибку - «Ошибка при получении».

Я хочу, чтобы при выборе какого-либо потока из таблицы Oracle возвращались строки, которые не были сохранены в другом открытом сеансе.

Могу ли я это сделать?

Ответы [ 4 ]

2 голосов
/ 01 октября 2009

Это набросок решения, которое я очень успешно использовал ранее:

  1. Используйте синтаксис SELECT FOR UPDATE NOWAIT, чтобы, если сеанс не может получить блокировку строки сразу, он вызывает исключение вместо ожидания блокировки. Обработчик исключений может подождать несколько секунд (например, с помощью dbms_lock.sleep); весь блок может быть заключен в цикл, который повторяется определенное количество раз, прежде чем он сдается.

  2. Добавьте WHERE ROWNUM<=n к запросу, чтобы он пытался получить только определенное количество строк (например, 1) за раз; если это успешно, обновите строки как "в процессе".

  3. Хороший способ пометить строки как «в процессе» (которые, как я видел, использовались успешно) - это иметь два столбца - SID и SERIAL # - и обновить эти столбцы с помощью SID и SERIAL # для текущего сессия.

  4. В случае сбоя сеанса, когда строки помечены как «в процессе», другой процесс может «очистить» строки, помеченные как «в процессе», путем поиска любых строк, имеющих SID / SERIAL # которые не найдены как активные сеансы в v$session.

2 голосов
/ 01 октября 2009

Oracle уже решил это за вас: используйте Advanced Queuing API

1 голос
/ 02 октября 2009

Если у вас есть 11 г, посмотрите на SKIP LOCKED Это есть, но без документов (и, следовательно, без поддержки и, возможно, с ошибками) в 10g. Таким образом, когда Сессия A блокирует строку, Сессия B может пропустить ее и обработать следующую.

0 голосов
/ 01 октября 2009

Одно решение:

  1. Поместите запросы выбора и обновления в транзакцию. Именно из-за этой проблемы были изобретены транзакции.

  2. Вам также нужно беспокоиться о «сиротских» строках - например, нить поднимает ряд и затем умирает, не заканчивая работу. Чтобы решить эту проблему, одно решение должно иметь 2 столбца: «IsInProcess» и «StartprocessingTime».

    isInProcess будет иметь 3 значения: 0 (не обработано), 1 (снято), 2 (выполнено).

    Исходная транзакция установит для строки "isInProcess" значение 1 и для параметра "StartprocessingTime" что-то еще, но оператор выбора также добавит это к предложению where (при условии, что вы можете указать допустимый период ожидания)

    "ГДЕ isInProcess = 0 ИЛИ (isInProcess = 1 И StartprocessingTime

    Обратите внимание, что приведенный выше синтаксис не ORACLE, просто псевдокод.

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