我用触发器实现了一个乐观锁,在过程中没有触发器怎么能实现呢?
我读了这篇文章实现乐观锁定
但我不明白我将如何在程序中执行它。
我试过这个,但我没有得到我期望的
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;