使用SQL / JDBC在OpenEdge 10.2B中正确实现自动递增主键

时间:2012-03-17 21:08:49

标签: progress-4gl openedge

我想模仿许多数据库在OpenEdge中具有的自动递增主键功能(即,在执行INSERT时不必指定主键值)使用JDBC适配器。到目前为止,我已经非常接近我需要的东西,除了能够访问数据库从INSERT返回时生成的主键值的部分(ahem,所以可能不是那么接近;)。) p>

我当前的解决方案使用表PK默认值,触发器和序列的组合,以便将其关闭:

CREATE TABLE users (
  id   BIGINT PRIMARY KEY DEFAULT -1,
  name VARCHAR(200)
);

CREATE SEQUENCE users_seq
START WITH 0,
INCREMENT BY 1,
NOCYCLE;

CREATE TRIGGER users_trigger
BEFORE INSERT ON users
REFERENCING NEWROW
FOR EACH ROW
IMPORT
import java.sql.*;
BEGIN
Long current_id = (Long)NEWROW.getValue(1, BIGINT);
if (current_id == -1) {
  SQLCursor next_id_query = new SQLCursor("SELECT TOP 1 users_seq.NEXTVAL FROM SYSPROGRESS.SYSCALCTABLE");
  next_id_query.open();
  next_id_query.fetch();
  Long next_id = (Long)next_id_query.getValue(1,BIGINT);
  next_id_query.close();
  NEWROW.setValue(1, next_id);
}
END

这允许我运行这样的插入语句:

INSERT INTO users(name) VALUES('Foo Bar')

并且新行自动从数据库触发器获取ID。那部分工作正常。

我现在真正需要的是设置ID的值;要么直接获取值,要么是包含刚刚插入的行的ResultSet(然后可以将其解包以查看ID)。我知道OraclePostgres都支持插入的RETURNING子句,这通常是如何处理的。但是,对于OpenEdge,我没有看到类似的内容。

我可以在10.2B SQL开发手册中找到的唯一相关部分在第5-10节中,其中显示了在执行CURRVAL后使用{INSERT访问序列的NEXTVAL {1}}。但是,如果在多个JDBC会话(竞争条件等等)中有大量的INSERT正在进行该表,那么这是危险的,因为我可以获得别人的ID。

到目前为止,我能想出的唯一选择是编写一个专门用于包装/执行INSERT操作的存储过程,该操作具有生成的ID的输出参数。但是,这对我正在处理的事情来说是不可行的,它必须使用简单的SQL INSERT语句,并且看起来有点hackish和脆弱(例如如何处理可能的值的不同组合和排列在INSERT上提供,如果架构发生变化会怎样?)。

此外,这一点的重点是不必引用INSERT中的主键,因此请不要告诉我在users_seq.NEXTVAL语句中使用INSERT。 : - )

2 个答案:

答案 0 :(得分:1)

没有可行的方法来实现这一点;用户必须指定PK的值或指定序列的名称,以便可以使用CURRVAL / NEXTVAL

一个不可行的解决方法是构造一个专门用于执行INSERT的特殊存储过程,但这不是一般解决方案,因为INSERT命令采用可变数量的参数(尤其是哪些列和数据到填充),而存储过程必须有固定数量的参数。

如果存在一个SQL函数,它将返回一个特殊的会话ID,该ID对应于客户端与SQL引擎的瞬时连接,则可以让客户端和触发器/存储过程使用预先确定的表作为请求队列(通过使用会话ID作为密钥)。不幸的是,根据文档,没有这样的会话ID。

答案 1 :(得分:-2)

1个愚蠢的问题...为什么使用此SQL代码更新Data in Progress DB? 它在4GL(相应的ABL)代码中变得更加容易......您应该在appserver上创建一个简单的创建过程或服务。 我从迁移工具(勺子)访问ODBC SQL时遇到了同样的问题。我必须放弃......