【发布时间】:2012-03-17 21:08:48
【问题描述】:
我想使用 JDBC 适配器模仿 OpenEdge 中许多数据库具有的自动递增主键功能(即在执行 INSERT 时不必指定主键值)。到目前为止,我已经非常接近我需要的东西,除了能够访问数据库在从 INSERT 返回时生成的主键值的部分(咳咳,所以可能不是那么接近;))。
我当前的解决方案使用 table 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 都支持插入的RETURNING 子句,这通常是如何处理的。但是,对于 OpenEdge,我没有看到类似的东西。
我可以在 10.2B SQL 开发手册中找到的唯一相关部分是第 5-10 节,其中显示了在执行使用 NEXTVAL 的 INSERT 之后如何访问序列的 CURRVAL。但是,这很危险,因为如果跨多个 JDBC 会话(竞争条件等)有大量 INSERTs 用于该表,我可能会获得其他人的 ID。
到目前为止,我能想到的唯一替代方法是编写一个专门用于包装/执行INSERT 操作的存储过程,该过程具有生成的 ID 的输出参数。但是,这对于我正在处理的工作来说是不可行的,它必须使用普通的 SQL INSERT 语句,而且看起来有点生硬和脆弱(例如,如何处理可以提供的值的不同组合和排列在INSERT 上,如果架构发生变化怎么办?)。
另外,这样做的重点是不必在 INSERT 中引用主键,所以请不要告诉我在我的 INSERT 语句中使用 users_seq.NEXTVAL。 :-)
【问题讨论】:
标签: progress-4gl openedge