有没有办法从最后插入的行中获取值?
我正在插入一行,由于序列创建,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,返回的值现在是一个奇怪的字符串值。
答案 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;
方法。