DB中最后一次插入行的值

时间:2009-12-29 19:57:31

标签: java database oracle jdbc

有没有办法从最后插入的行中获取值?

我正在插入一行,由于序列创建,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,返回的值现在是一个奇怪的字符串值。

3 个答案:

答案 0 :(得分:10)

您要做的是利用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);

答案 1 :(得分:4)

这与其他数据库不一致,但在使用Oracle时,getGeneratedKeys()在使用Statement.RETURN_GENERATEDKEYS时返回插入行的ROWID。因此,您需要使用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时,您应该使用方法executeUpdate(String sql, int[] columnIndexes)executeUpdate(String sql, String[] columnNames)而不是executeUpdate(String sql, int autoGeneratedKeys)来获取生成的序列值。像这样的东西(调整值以匹配索引或主键列的名称):

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

stmt.executeUpdate(INSERT_SQL, new String[] {"ID"});
ResultSet rs = stmt.getGeneratedKeys();

在对此进行更多挖掘的同时,似乎这种方法显示在Spring documentation中(如上所述here)所以,我想这不可能是完全错误的。但是,不幸的是,它不是真正可移植的,它可能无法在其他平台上运行。

答案 2 :(得分:2)

您应该使用ResultSet#getLong()代替。如果徒劳无功,请尝试ResultSet#getRowId()并最终将其投放到oracle.sql.ROWID。如果返回的十六进制字符串实际上是十六进制风格的ID,那么您可以尝试通过Long#valueOf()Integer#valueOf()将其转换为十进制。

Long id = Long.valueOf(hexId, 16);

也就是说,Oracle的JDBC驱动程序长时间不支持ResultSet#getGeneratedKeys(),并且仍然有点麻烦。如果你无法做到这一点,那么你需要在SELECT CURRVAL(sequencename)的同一语句上执行insert,或者在同一事务中执行新语句,如果它是{{1 }}。基本示例:

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);
    }
}

完全是多余的。去掉它。

您可以找到here我之前发布的关于获取生成的密钥的另一个示例,它使用正常的stmt.RETURN_GENERATED_KEYS; 方法。