Может ли пользователь Oracle получить список своих запущенных сеансов без доступа к v $ session? - PullRequest
2 голосов
/ 17 июня 2010

У меня есть приложение, которое запускает процесс, и я хочу, чтобы одновременно запускался только один процесс.Вот некоторые варианты:

  1. Использование блокировки объекта для предотвращения запуска последующих процессов.

    Это было бы хорошо, но я хочу, чтобы вызывающий сеанс немедленно возвращался, а не ожидалтекущий сеанс завершен.

  2. Используйте пользовательский Y / N, чтобы указать, запущен процесс или нет.

    Я установил флаг "Y" в началепроцесса и установите его на «N», когда он заканчивается или не удается.Тоже хорошо, но мне кажется, что я заново изобретаю колесо, и мне не хочется идти дальше.Он также не срабатывает, если текущий сеанс прерывается, поскольку флаг остается на «Y».

  3. Использование dbms_application_info.set_module

    Этот подход кажется наиболее надежным, но еслиЯ должен знать, что уже существует запущенный процесс, который, я думаю, мне нужно иметь возможность запрашивать v$session, и я не хочу, чтобы это приложение имело такой широкий доступ.

Любые идеи

Ответы [ 3 ]

6 голосов
/ 17 июня 2010

Вариант 4: использовать DBMS_LOCK для сериализации доступа. Вот ссылка на документацию: http://download.oracle.com/docs/cd/E11882_01/appdev.112/e10577/d_lock.htm#i1002556

Пример:

Сначала создайте вспомогательную процедуру для сериализации доступа к определенной процедуре. Процедура использует имя процедуры для генерации уникального дескриптора блокировки. «NOTORA $», чтобы убедиться, что имя замка не начинается с «ORA $», поскольку оно зарезервировано для Oracle.

SQL> create procedure serialize_access (p_procedure_name in varchar2)
  2  is
  3    l_lockhandle varchar2(128);
  4    l_return     integer;
  5  begin
  6    dbms_lock.allocate_unique
  7    ( lockname   => 'NOTORA$' || p_procedure_name
  8    , lockhandle => l_lockhandle
  9    );
 10    l_return := dbms_lock.request
 11    ( lockhandle        => l_lockhandle
 12    , lockmode          => dbms_lock.x_mode
 13    , timeout           => 0  -- do not wait
 14    , release_on_commit => true
 15    );
 16    if l_return = 1
 17    then
 18      raise_application_error
 19      ( -20000
 20      , 'Someone else is running this procedure, so you''ll have to wait'
 21      );
 22    end if;
 23  end serialize_access;
 24  /

Procedure created.

В вашей процедуре вызовите эту процедуру serialize_access следующим образом:

SQL> create procedure p1
  2  is
  3  begin
  4    serialize_access('p1');
  5    dbms_lock.sleep(30);
  6  end;
  7  /

Procedure created.

Где dbms_lock.sleep используется в качестве замены вашего реального кода. Теперь откройте два или более других сеанса и введите команду «exec p1». Первый сеанс начнется с ожидания 30 секунд. Вторая сессия покажет вам это:

ERROR at line 1:
ORA-20000: Someone else is running this procedure, so you'll have to wait
ORA-06512: at "[schema].SERIALIZE_ACCESS", line 18
ORA-06512: at "[schema].P1", line 4
ORA-06512: at line 1

Надеюсь, это поможет.

С уважением, Роб.

1 голос
/ 18 июня 2010

Ответ DBMS_LOCK очень хороший, но кажется немного сложным ... но это сложность однократной настройки, так что все в порядке.

Очень простой способ - создать таблицу конфигурации ... может иметь один столбец 'name'

Если вы хотите заблокировать, сделайте:

ВЫБРАТЬ имя INTO var FROM config WHERE name = 'lock_name' FOR UPDATE NOWAIT;

Ловушка для ошибки, когда она терпит неудачу на NOWAIT.

То, как вы снимаете эту блокировку, происходит с помощью COMMIT; или ROLLBACK; что будет делать ваша сессия, если она умрет (обычно).

Вы можете добавить в таблицу больше строк, если появятся новые однопоточные процессы. Вы даже можете изменить NOWAIT на WAIT n. Таким образом, следующие экземпляры могут подождать 10 секунд или еще что-нибудь, чтобы увидеть, сможет ли он получить блокировку. Это был бы лучший способ сохранить "Всегда в курсе"

1 голос
/ 17 июня 2010

Я бы предпочел # 3 - если вы не хотите, чтобы пользователь имел доступ к v $ session, запишите желаемую функциональность в функцию пакета, принадлежащую другой схеме, и верните статус am_I_running.Тогда вам нужно только предоставить EXECUTE для этой функции интересующим пользователям.

В производстве # 1 / # 2 обычно требуется ручное вмешательство, когда сеанс завершается неудачей или зависает.

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