Как использовать оптимистическую блокировку внутри процедуры? - PullRequest
0 голосов
/ 11 ноября 2018

Я реализовал оптимистическую блокировку с триггером, как я могу сделать это без триггера в процедуре?

Я читаю этот пост Реалистичная оптимистическая блокировка

Но я не понимаю, как я буду реализовывать это в процедуре.

Я попробовал это, но я не получил то, что ожидал

SQL> CREATE OR REPLACE PACKAGE BODY account_api AS
  2       PROCEDURE upd_account
  3          (p_acc_id     accounts.acc_id%type
  4            , p_acc_name   accounts.acc_name%type
  5            , p_acc_amount accounts.acc_amount%type
  6            , p_acc_date   accounts.acc_date%type
  7          , p_acc_version accounts.acc_version%type
  8          )
  9           IS
 10         BEGIN
 11             UPDATE accounts
 12             set acc_name    = acc_name
 13           , acc_amount  = acc_amount
 14           , acc_date    = acc_date
 15           , acc_version = acc_version + 1
 16     where acc_id   = p_acc_id
 17     and  acc_version = p_acc_version;
 18  if(SQL%ROWCOUNT = 0)
 19  THEN
 20  RAISE_APPLICATION_ERROR( -20001, 'Oops, the row has changed since you read it.' );
 21  END IF;
 22   END;
 23   end account_api;
 24  /

SQL> begin
  2  account_api.upd_account(1, 'user12', 1200, sysdate, '11-NOV-18 06.10.01.660948 AM');
  3   end;
  4  /
PL/SQL procedure successfully completed.

Я пытаюсь код с той же отметкой времени, и теперь это сделано

   SQL> begin
      2  account_api.upd_account(1, 'user1', 1200, sysdate, '11-NOV-18 06.10.01.660948 AM');
      3   end;
      4  /
    PL/SQL procedure successfully completed.

Ответы [ 2 ]

0 голосов
/ 12 ноября 2018

Это то, чего я хотел достичь

   PROCEDURE upd_account
                    (   p_acc_id      accounts.acc_id%type
                      , p_acc_name    accounts.acc_name%type
                      , p_acc_amount  accounts.acc_amount%type
                      , p_acc_date    accounts.acc_date%type
                      , p_version     accounts.version%type
                    )
                     IS
                  BEGIN
                      UPDATE accounts
                      set acc_name    = p_acc_name
                    , acc_amount  = p_acc_amount
                    , acc_date    = p_acc_date
                    , version = p_version + 1
             where acc_id = p_acc_id
             and version = p_version;
             DBMS_OUTPUT.PUT_LINE ('Number of updated records: ' || TO_CHAR(SQL%ROWCOUNT));
          if(SQL%ROWCOUNT = 0)
          THEN
          RAISE_APPLICATION_ERROR( -20001, 'Oops, the row has changed since you read it.' );
          END IF;
           END;
0 голосов
/ 11 ноября 2018

Идея состоит в том, что вы сначала выбрали бы запись (с помощью запроса select), а затем решили обновить ее. Вы указали правильную процедуру. Требуется передать ему значение acc_version в качестве последнего аргумента. У вас есть это значение из запрашиваемой вами записи.

Это тип контракта, которому вы должны следовать: вам нужно запросить этот acc_version и затем передать его процедуре для обновления, которое вы хотите сделать. После каждого обновления вы должны повторно запрашивать текущее значение acc_version, если вам все еще нужно сделать больше обновлений.

Поле app_version должно быть числом (не датой). Он предназначен для отражения версии записи, такой как версия 1, 2, 3, ..., которая может рассматриваться как число обновлений, которые были сделаны для этой конкретной записи.

Процедура выполнит обновление при условии , что это значение в записи не обновлялось за среднее время (каким-либо другим обновлением). Для этой проверки используется простое предложение where.

Если обновление ничего не обновляет, то это означает, что запись больше не удовлетворяет этому условию (и была изменена). В этом случае возникает исключение.

Но если acc_version все еще остается таким же, как вы передали его процедуре, оператор update действительно обновит целевую запись. В то же время оператор update увеличивает acc_version. Это не позволит другим клиентам, которые уже запросили эту запись до этого обновления, выполнять обновления. Им нужно будет повторно запросить запись, чтобы получить правильное значение acc_version, и повторить попытку.

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