我想使用 JDBC 适配器模仿 OpenEdge 中许多数据库具有的自动递增主键功能(即在执行插入时不必指定主键值(。 到目前为止,我已经非常接近我需要的,除了能够访问数据库从 INSERT 返回时生成的主键值的部分(咳咳,所以可能不是那么接近;)(。
我当前的解决方案使用表 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(。 我知道 Oracle 和 Postgres 都支持插入的 RETURN 子句,这通常是如何处理的。 但是,我没有看到OpenEdge这样的东西。
我在 10.2B SQL 开发手册中找到的唯一相关部分在第 5-10 节中,它展示了如何在执行使用 NEXTVAL
的INSERT
后访问序列的CURRVAL
。 但是,这很危险,因为如果该表在多个 JDBC 会话(竞争条件等(中进行大量INSERT
,我可以获取其他人的 ID。
到目前为止,我能想到的唯一替代方案是编写一个专门用于包装/执行INSERT
操作的存储过程,该过程具有生成的 ID 的输出参数。 但是,这对于我正在做的事情来说是不可行的,它必须使用普通的 SQL INSERT
语句,而且似乎有点黑客和脆弱(例如,如何处理可以在INSERT
上提供的不同组合和排列值,如果模式更改怎么办?
另外,这样做的重点是不必在插入中引用主键,所以请不要告诉我在我的INSERT
语句中使用users_seq.NEXTVAL
。
没有可行的方法来实现这一点;用户必须为 PK 指定一个值或指定序列的名称,以便可以使用 CURRVAL
/NEXTVAL
。
一个不可行的解决方法是构造一个专门用于执行 INSERT(s( 的特殊存储过程,但这不是一个通用的解决方案,因为 INSERT 命令采用可变数量的参数(其中最重要的是要填充哪些列和数据(,而存储过程必须具有固定数量的参数。
如果存在一个 SQL 函数,该函数将返回与客户端与 SQL 引擎的瞬态连接相对应的特殊会话 ID,则可以让客户端和触发器/存储过程使用预先确定的表作为请求队列进行通信(通过使用会话 ID 作为键(。不幸的是,根据文档,没有这样的会话 ID。
1 个愚蠢的问题...为什么要使用此 SQL 代码来更新正在进行的数据库中的数据?在 4GL(或 ABL(代码中它变得更加容易......您应该在应用程序服务器上创建简单的创建过程或服务。我从迁移工具(勺子(访问 ODBC SQL 时遇到了同样的问题。我必须放弃...