8

我正在重构企业应用程序的数据导入过程,并遇到了一个片段,我想找到一个更好的解决方案。导入数据时,我们必须为每个数据集创建一个唯一实体,并且在字段中有一个计数器用于按顺序分配此 ID。您阅读该字段以获取下一个空闲 ID,然后将其递增以准备下一次。

目前,这是在原始应用程序中分两步完成的,用“C”编写:

   SELECT idnext FROM mytable;
   UPDATE mytable SET idnext = idnext + 1;

如果多个进程做同样的事情,显然这里存在竞争条件。

编辑:重要的并存条件:我无法触及数据库/字段定义,这排除了序列。

我们正在用 perl 重写,我想做同样的事情,但更好。原子解决方案会很好。不幸的是,我的 SQL 技能有限,所以我求助于集体智慧 :-)

4

4 回答 4

9

在这种特殊情况下,如前所述,序列是正确的解决方案。但是,如果在将来的某些情况下,您需要在同一语句中更新某些内容并返回一个值,则可以使用该RETURNING子句:

UPDATE atable SET foo = do_something_with(foo) RETURNING foo INTO ?

如果调用代码是 PL/SQL,请替换 ? 使用本地 PL/SQL 变量;否则,您可以将其绑定为程序中的输出参数。

编辑:既然你提到了 Perl,这样的东西应该可以工作(未经测试):

my $sth = $dbh->prepare('UPDATE mytable SET idnext = idnext + 1 returning idnext into ?');
my $idnext;
$sth->bind_param_inout(1, \$idnext, 8);
$sth->execute; # now $idnext should contain the value

请参阅DBI

于 2010-01-08T17:27:18.677 回答
4

为什么不使用序列

使用您想要的任何 START WITH 值创建一次序列:

CREATE SEQUENCE mysequence
  START WITH 1
  MAXVALUE 999999999999999999999999999
  MINVALUE 1
  NOCYCLE
  NOCACHE
  NOORDER;

然后在运行时的应用程序代码中,您可以使用此语句获取下一个值:

SELECT mysequence.NEXTVAL
  INTO idnext
  FROM DUAL;

更新:使用序列将是首选方法,但由于您无法更改数据库,所以我同意使用 RETURNING 应该适用于您的情况:

   UPDATE mytable 
      SET idnext = idnext + 1 
RETURNING idnext 
     INTO mylocalvariable;
于 2010-01-08T17:18:52.090 回答
2

使用 SELECT FOR UPDATE 语句。它保证对记录的互斥权:

“选择更新;

于 2010-01-08T17:31:20.553 回答
0

一个序列将完成这项工作,看看例如Oracle 序列

于 2010-01-08T17:18:06.073 回答