Как безопасно сбросить последовательность Oracle? - PullRequest
0 голосов
/ 23 мая 2019

Я хочу каждый день сбрасывать свою последовательность Oracle на 0, мой код выглядит так:

create or replace procedure reset_seq(p_seq_name in varchar2) is
  l_val number;
begin
  execute immediate 'select ' || p_seq_name || '.nextval from dual'
    INTO l_val;   --1

  execute immediate 'alter sequence ' || p_seq_name || ' increment by -' ||
                    l_val || ' minvalue 0'; --2
  execute immediate 'select ' || p_seq_name || '.nextval from dual'
    INTO l_val;  --3

  execute immediate 'alter sequence ' || p_seq_name ||
                    ' increment by 1 minvalue 0';  --4

end;

, но после запуска примерно через 2 года внезапно я получаю ошибку, инкремент отрицательный, например, -16и начальное значение также составляет -16.Так что любой может помочь мне объяснить эту проблему.

Я думаю, что.

  1. процедура запускается до шага 3, после чего текущий прирост равен -16, а nextval равен 0.
  2. другой клиент запрашивает последовательность, но текущий прирост равен -16, поэтому следующее значение равно -16
  3. исключение произошло при выполнении процедуры до шага 4.

но я не уверен в этом, кто-нибудь может мне это объяснить.Спасибо.

1 Ответ

0 голосов
/ 23 мая 2019

Проблема заключается в том, что и ваша заявленная на работу процедура, и ваша внешняя программа могут вызывать nextval между шагами 2 и 4; и мог позвонить в любом порядке; и потенциально внешняя программа может сделать несколько звонков.

Вы можете попытаться уменьшить это, изменив и процедуру, и внешний вызов.

В настоящий момент, если на шаге 3 произошла ошибка, процедура завершается, а шаг 4 так и не достигается, поэтому все будущие вызовы на nextval продолжат с ошибкой. Таким образом, вы можете перехватывать и игнорировать ошибку ORA-08004, исходя из того, что вы получите только то, что если между шагами 2 и 3 произошел внешний вызов, последовательность была увеличена до нуля этим вызовом и, таким образом, пошагово 3 в данном сценарии фактически избыточен:

create or replace procedure reset_seq(p_seq_name in varchar2) is
  l_val number;
  e_8004 exception;
  pragma exception_init(e_8004, -8004);
begin
  execute immediate 'select ' || p_seq_name || '.nextval from dual'
    INTO l_val;   --1

  execute immediate 'alter sequence ' || p_seq_name || ' increment by -' ||
                    l_val || ' minvalue 0'; --2

  begin
    execute immediate 'select ' || p_seq_name || '.nextval from dual'
      INTO l_val;  --3
  exception
    when e_8004 then
      -- nextval has already been called by someone else
      null;
  end;

  execute immediate 'alter sequence ' || p_seq_name ||
                    ' increment by 1 minvalue 0';  --4

end;

Теперь, если внешняя программа вызывает nextval между шагами 2 и 3, вы получите ошибку на шаге 3, но проигнорируете ее, и шаг 4 все равно будет выполнен.

Ваша внешняя программа получит значение nextval, равное нулю, если она выполнит вызов между шагами 2 и 3; и получит ORA-08004, если он вызывает между шагами 3 и 4 - или если он делает несколько вызовов в окне между шагами 2 и 4. Итак, предположим, что вы не ожидаете, что ноль будет действительным результатом (что кажется разумным, так как как правило, вы этого никогда не получите), вы можете совершать повторные звонки, пока не получите ненулевой ответ и без ошибок. В псевдокоде что-то вроде:

loop
  val = seq.nextval;
  if error == -8004 then continue;
  if val == 0 then continue;
  break;
end loop

Вы могли бы подумать о том, чтобы поместить эту логику в функцию PL / SQL и заставить вашу программу вызывать функцию вместо прямого доступа к последовательности, чтобы скрыть эту сложность и избежать необходимости повторять ее, если потенциально затрагивается более одной программы. .

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