select ... for update
是你应该采取的第一步;如果没有它,你就不能为进一步处理“保留”该行(除非你愿意以独占模式锁定整个表;如果那个“处理”需要不花费时间,那也可以是一个选项,特别是如果将要执行此操作的用户不多)。
如果行存在,其余部分很简单-处理它,更新它,提交。
但是,如果不存在,你将不得不插入一个新行(正如你所说),这里有两个(或更多)用户插入相同值的问题。
为了避免这种情况,创建一个函数,它
- 将为新行返回唯一的
ID
值
- 是一个自主事务
- 为什么?因为你在其中执行DML(update或insert),除非它是自主事务,否则你不能在函数中执行DML
用户将不得不使用该函数来获取下一个ID
值。以下是一个示例:你将需要一个表(my_id
),它保存了最后使用的ID(每个通过函数访问它的用户都将创建一个新值)。
表格:
SQL> create table my_id (id number);
Table created.
功能:
SQL> create or replace function f_id
2 return number
3 is
4 pragma autonomous_transaction;
5 l_nextval number;
6 begin
7 select id + 1
8 into l_nextval
9 from my_id
10 for update of id;
11
12 update my_id set
13 id = l_nextval;
14
15 commit;
16 return (l_nextval);
17
18 exception
19 when no_data_found then
20 lock table my_id in exclusive mode;
21
22 insert into my_id (id)
23 values (1);
24
25 commit;
26 return(1);
27 end;
28 /
Function created.
作为使用
SQL> select f_id from dual;
F_ID
1
SQL>
就是这样...你将使用的代码将类似于这样:
SQL> create table test
2 (id number constraint pk_test primary key,
3 name varchar2(10),
4 datum date
5 );
Table created.
SQL> create or replace procedure p_test (par_id in number)
2 is
3 l_id test.id%type;
4 begin
5 select id
6 into l_id
7 from test
8 where id = par_id
9 for update;
10
11 update test set datum = sysdate where id = par_id;
12 exception
13 when no_data_found then
14 insert into test (id, name, datum)
15 values (f_id, 'Little', sysdate);
16 end;
17 /
Procedure created.
SQL> exec p_test (1);
PL/SQL procedure successfully completed.
SQL> select * from test;
ID NAME DATUM
1 Little 04.09.2021 20:49:21
SQL> exec p_test (1);
PL/SQL procedure successfully completed.
SQL> select * from test;
ID NAME DATUM
1 Little 04.09.2021 20:49:21
SQL> exec p_test (1);
PL/SQL procedure successfully completed.
SQL> select * from test;
ID NAME DATUM
1 Little 04.09.2021 20:49:30
SQL>
merge
,但是你在问题中没有提供足够的细节来描述你的确切问题。 - Gordon Linoffmerge
没有一个returning into
选项。 - eaolson