我使用触发器实现了乐观锁,如何在过程中不使用触发器的情况下做到这一点?
我读了这篇文章Implementic Optimistic Locking
但是我不明白如何在程序中实现它。
我尝试了这个,但没有达到我的期望
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.
答案 0 :(得分:2)
这个想法是,您将首先选择一条记录(通过select
查询),然后决定对其进行更新。您引用的过程是正确的。它要求您将acc_version
的值作为最后一个参数传递给它。您可以从查询的记录中获得该值。
这是您必须遵循的一种合同:您需要查询acc_version
,然后将其传递给要进行更新的过程。每次更新后,如果仍然需要进行更多更新,则必须重新查询acc_version
的当前值。
app_version
字段必须是数字(而不是日期)。它旨在反映记录的版本,例如版本1、2、3,...,这可以看作是对该特定记录进行的更新次数。
该过程将在以下条件下进行更新: ,即记录中的此值在此期间未更新(通过其他更新)。它使用简单的where
子句进行检查。
如果更新不更新任何内容,则意味着记录不再满足此条件(并且已被更改)。在这种情况下,会引发异常。
但是,如果acc_version
仍在传递给过程时仍然有效,则update
语句确实会更新目标记录。同时,update
语句递增acc_version
。这样可以防止已经在此更新之前 查询此记录的其他客户端进行更新。他们将需要重新查询记录以获得正确的acc_version
值,然后重试。
答案 1 :(得分:0)
这是我想要实现的
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;