如何在过程中使用乐观锁定



我用触发器实现了一个乐观锁,在过程中没有触发器怎么能实现呢?

我读了这篇文章实现乐观锁定

但我不明白我将如何在程序中执行它。

我试过这个,但我没有得到我期望的

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.

我们的想法是,您将首先选择一条记录(通过select查询(,然后决定更新它。您引用的过程是正确的。它要求您将acc_version的值作为最后一个参数传递给它。您从查询的记录中获得了该值。

这是一种您必须遵循的契约:您需要查询acc_version,然后将其传递给要进行更新的过程。每次更新后,如果还需要进行更多更新,则必须重新查询acc_version的当前值。

app_version字段必须是一个数字(而不是日期(。它旨在反映记录的版本,如版本1、2、3。。。其可以被视为已经对该特定记录进行的更新的数量。

该程序将在的条件下进行更新,即记录中的该值在平均时间内没有更新(通过其他更新(。它使用一个简单的where子句进行该检查。

如果更新没有更新任何内容,则意味着记录不再满足此条件(并且已被更改(。在这种情况下,将引发异常。

但是,如果acc_version在您将其传递给过程时仍然存在,那么update语句确实会更新目标记录。同时,update语句递增acc_version。这将阻止在此更新之前已经查询过此记录的其他客户端进行更新。他们需要重新查询记录以获得正确的acc_version值,然后重试。

这就是我想要实现的

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;

最新更新