Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/360.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 上次插入行的值(以DB为单位)_Java_Database_Oracle_Jdbc - Fatal编程技术网

Java 上次插入行的值(以DB为单位)

Java 上次插入行的值(以DB为单位),java,database,oracle,jdbc,Java,Database,Oracle,Jdbc,是否有某种方法可以从最后插入的行中获取值 我正在插入一行,由于创建了序列,PK将自动增加,我想得到这个序列号。只有PK在表中保证是唯一的 我将Java与JDBC和Oracle一起使用 我忘了添加我想使用下面的结果集检索这个值。我已经在mysql上尝试过了,它成功地工作了,但是我不得不切换到Oracle,现在我得到了ID的字符串表示,而不是实际的序列号 Statement stmt = conn.createStatement(); stmt.executeUpdate(insertCmd, St

是否有某种方法可以从最后插入的行中获取值

我正在插入一行,由于创建了序列,PK将自动增加,我想得到这个序列号。只有PK在表中保证是唯一的

我将Java与JDBC和Oracle一起使用

我忘了添加我想使用下面的结果集检索这个值。我已经在mysql上尝试过了,它成功地工作了,但是我不得不切换到Oracle,现在我得到了ID的字符串表示,而不是实际的序列号

Statement stmt = conn.createStatement();
stmt.executeUpdate(insertCmd, Statement.RETURN_GENERATED_KEYS);
stmt.RETURN_GENERATED_KEYS;
ResultSet rs = stmt.getGeneratedKeys();
if(rs.next()){
   log.info("Successful insert");
   id = rs.getString(1);
}
上面的代码段将返回存储在mysql表中的列int值。但由于我已经切换到Oracle,返回的值现在是一个奇怪的字符串值。

您应该使用ResultSetLong。如果无效,请尝试ResultSetgetRowId并最终将其强制转换为oracle.sql.ROWID。如果返回的十六进制字符串实际上是十六进制格式的ID,那么可以尝试通过LongvalueOf或IntegervalueOf将其转换为十进制

也就是说,Oracle的JDBC驱动程序很长一段时间都不支持ResultSetGeneratedKeys,并且仍然有点麻烦。如果不能正确执行此操作,则需要在执行insert的同一语句上执行SELECT CURRVALSENQUENCENAME,或者在同一事务中执行新语句(如果它是PreparedStatement)。基本示例:

public void create(User user) throws SQLException {
    Connection connection = null;
    PreparedStatement preparedStatement = null;
    Statement statement = null;
    ResultSet generatedKeys = null;

    try {
        connection = daoFactory.getConnection();
        preparedStatement = connection.prepareStatement(SQL_INSERT);
        preparedStatement.setValue(1, user.getName());
        // Set more values here.
        int affectedRows = preparedStatement.executeUpdate();
        if (affectedRows == 0) {
            throw new SQLException("Creating user failed, no rows affected.");
        }
        statement = connection.createStatement();
        generatedKeys = statement.executeQuery(SQL_CURRVAL);
        if (generatedKeys.next()) {
            user.setId(generatedKeys.getLong(1));
        } else {
            throw new SQLException("Creating user failed, no generated key obtained.");
        }
    } finally {
        close(generatedKeys);
        close(statement);
        close(preparedStatement);
        close(connection);
    }
}
哦,根据您的代码示例,下面一行

stmt.RETURN_GENERATED_KEYS;
这完全是多余的。移除它


您可以找到我之前发布的另一个关于获取生成键的示例,它使用普通的getGeneratedKeys方法。

这与其他数据库不一致,但是,在使用Oracle时,getGeneratedKeys在使用语句时返回插入行的ROWID。RETURN\u GENERATEDKEYS。因此,您需要使用oracle.sql.ROWID专有类型来读取它:

Statement stmt = connection.createStatement();
stmt.executeUpdate(insertCmd, Statement.RETURN_GENERATED_KEYS);
ResultSet rs = stmt.getGeneratedKeys();
oracle.sql.ROWID rid = (oracle.sql.ROWID) rs.getObject(1); 
但这不会给你PK的生成ID。使用Oracle时,应使用方法或而不是获取生成的序列值。如下所示,调整值以匹配索引或主键列的名称:

stmt.executeUpdate(INSERT_SQL, new int[] {1});
ResultSet rs = stmt.getGeneratedKeys();


虽然在这方面进行了更多的挖掘,但这种方法似乎如前所述,所以,我想它不可能完全错误。但是,不幸的是,它不是真正可移植的,并且可能无法在其他平台上工作。

您试图做的是利用RETURNING子句。让我们设置一个示例表和序列:

CREATE TABLE "TEST" 
( "ID" NUMBER NOT NULL ENABLE, 
 "NAME" VARCHAR2(100 CHAR) NOT NULL ENABLE, 
  CONSTRAINT "PK_TEST" PRIMARY KEY ("ID")
  );

CREATE SEQUENCE SEQ_TEST;
现在,您的Java代码应该如下所示:

String insertSql = "BEGIN INSERT INTO TEST (ID, NAME) VALUES (SEQ_TEST.NEXTVAL(), ?) RETURNING ID INTO ?; END;";
java.sql.CallableStatement stmt = conn.prepareCall(insertSql);
stmt.setString(1, "John Smith");
stmt.registerOutParameter(2, java.sql.Types.VARCHAR);
stmt.execute();
int id = stmt.getInt(2);

你看到这个了吗@Nathan是的,我看到了,我刚刚用一个例子更新了我的问题,这个例子类似于你刚才发布的链接。这个问题不是链接问题的重复,因为这个问题是针对Oracle的,另一个问题是针对PostgreSQL的。由于Oracle和PostgreSQL之间的功能差异,其他问题的顶部答案不能用作此问题的答案。getGeneratedKeys中返回的唯一列是ROWID-Oracle11。我想这就是你提到的奇怪的值。我试了很长时间,结果都不起作用。返回的错误是无效的列类型:getLong未为类oracle.jdbc.driver.T4CRowidAccessor实现。我将尝试您的第二个建议。请尝试java.sql.RowId或oracle.sql.RowId。以下选项:oracle.sql.RowId rid=rs.getObject1;ID=rid.stringValue;ID包含一个十六进制值,这正是我之前使用rs.getString1得到的值;我会试试你最后的建议。也许它只是十六进制格式的ID。尝试将其转换为十进制。您的建议应该有效,但可能是因为我从oracle.sql.ROWID返回的值不是十六进制值?我得到以下错误:java.lang.NumberFormatException:对于输入字符串:AAAS+xaagaaaevaap~~~~引号中的值是我从ROWID.stringValue返回的值;没有成功,我有语法错误。我会看看我做错了什么,并给出更新。我不明白Pascal的意思是你反对RETURNING子句,但提出了一个需要两次数据库调用的解决方案。Adam的解决方案的好处是它只需要一个数据库调用。@David我不太喜欢触发器,主要是因为它们在幕后秘密地做一些神奇的事情,因为我不认为在Java和数据库上传播逻辑是个好主意。所以,如果我能避开它们,我就不使用它们。关于两个数据库调用,你能详细说明一下吗,我不确定我是否在跟踪你。这太棒了,我评论这一点只是为了记住这个黑客:我真的认为使用触发器是一个可怕的解决方案:它使代码更加不可移植,并增加了额外的复杂性。最初的问题是,我插入了一行,其中PK将因创建的序列而自动增加。。。。如果不使用触发器填充主键,您在Oracle中如何执行此操作?@Pascal该触发器是绝对可移植的。@Ada
m使用触发器是绝对不必要的,您可以在INSERT语句中包含seq.nextval。不,真的,我觉得这种方法不必要的麻烦,我不明白人们为什么喜欢它。我没有说我喜欢,但我基于这个问题做出了一个假设。是的,我想这确实让我的答案有点复杂。我可能会更新SQL,但我的答案的关键是使用RETURNING子句来获取PK的值。
CREATE TABLE "TEST" 
( "ID" NUMBER NOT NULL ENABLE, 
 "NAME" VARCHAR2(100 CHAR) NOT NULL ENABLE, 
  CONSTRAINT "PK_TEST" PRIMARY KEY ("ID")
  );

CREATE SEQUENCE SEQ_TEST;
String insertSql = "BEGIN INSERT INTO TEST (ID, NAME) VALUES (SEQ_TEST.NEXTVAL(), ?) RETURNING ID INTO ?; END;";
java.sql.CallableStatement stmt = conn.prepareCall(insertSql);
stmt.setString(1, "John Smith");
stmt.registerOutParameter(2, java.sql.Types.VARCHAR);
stmt.execute();
int id = stmt.getInt(2);