如何在JDBC中获得插入的ID?
在使用Statement.RETURN_GENERATED_KEYS时遇到“Unsupported feature”错误时,请尝试以下方法:
String[] returnId = { "BATCHID" }; String sql = "INSERT INTO BATCH (BATCHNAME) VALUES ('aaaaaaa')"; PreparedStatement statement = connection.prepareStatement(sql, returnId); int affectedRows = statement.executeUpdate(); if (affectedRows == 0) { throw new SQLException("Creating user failed, no rows affected."); } try (ResultSet rs = statement.getGeneratedKeys()) { if (rs.next()) { System.out.println(rs.getInt(1)); } rs.close(); }
其中,BATCHID是自动生成的ID。
这段代码的目的是在执行插入操作后获取生成的ID。首先,我们定义了一个名为returnId的字符串数组,其中包含了我们希望获取的生成的ID的字段名(在这个例子中就是BATCHID)。然后,我们构建了一个INSERT语句,并将returnId传递给PreparedStatement的构造函数。接下来,我们执行了更新操作,并通过判断受影响的行数来确保插入操作成功。最后,我们通过调用statement.getGeneratedKeys()方法获取生成的ID,并通过ResultSet对象来获取结果。
通过以上的方法,我们可以在JDBC中获取插入操作后生成的ID。
在JDBC中,有时候我们需要获取在数据库中插入的记录的ID。然而,JDBC并没有提供直接的方法来获取插入的ID,因此我们需要找到一种解决方案。
解决方案如下:
1. 首先,我们可以创建一个生成的列数组,其中包含我们想要获取的ID列。在这个例子中,我们将列名设置为"ID"。
String generatedColumns[] = { "ID" };
2. 接下来,我们需要将生成的列数组传递给我们的PreparedStatement对象,以便在执行插入操作时获取插入的ID。
PreparedStatement stmtInsert = conn.prepareStatement(insertSQL, generatedColumns);
3. 然后,我们可以使用ResultSet对象来获取Statement上的生成的键。我们可以使用next()方法来遍历结果集,并使用getLong()方法来获取生成的ID。在这个例子中,我们将获取的ID打印到控制台上。
ResultSet rs = stmtInsert.getGeneratedKeys(); if (rs.next()) { long id = rs.getLong(1); System.out.println("Inserted ID -" + id); }
通过这种方式,我们可以成功地获取插入的记录的ID。
以上就是如何在JDBC中获取插入的ID的解决方法。通过创建生成的列数组,并将其传递给PreparedStatement对象,然后使用ResultSet对象来获取生成的键,我们可以轻松地获取插入的记录的ID。
在JDBC中如何获取插入ID?
如果是由数据库自动生成的键,那么可以使用Statement#getGeneratedKeys()来获取。需要在与INSERT相同的Statement上调用该方法。首先需要创建Statement时,使用Statement.RETURN_GENERATED_KEYS参数来通知JDBC驱动程序返回生成的键。
以下是一个基本的示例:
public void create(User user) throws SQLException { try ( Connection connection = dataSource.getConnection(); PreparedStatement statement = connection.prepareStatement(SQL_INSERT, Statement.RETURN_GENERATED_KEYS); ) { statement.setString(1, user.getName()); statement.setString(2, user.getPassword()); statement.setString(3, user.getEmail()); // ... int affectedRows = statement.executeUpdate(); if (affectedRows == 0) { throw new SQLException("Creating user failed, no rows affected."); } try (ResultSet generatedKeys = statement.getGeneratedKeys()) { if (generatedKeys.next()) { user.setId(generatedKeys.getLong(1)); } else { throw new SQLException("Creating user failed, no ID obtained."); } } } }
需要注意的是,是否可行取决于JDBC驱动程序。目前,大多数最新版本的驱动程序都可以正常工作,但据我所知,Oracle JDBC驱动程序在这方面仍存在一些问题。MySQL和DB2早就支持这个功能,PostgreSQL不久前也开始支持。关于MSSQL,我无法评论,因为我从未使用过。
对于Oracle,可以在同一事务中在INSERT之后直接调用带RETURNING子句的CallableStatement或SELECT CURRVAL(sequencename)(或其他DB特定的语法)来获取最后生成的键。详见这个答案。
最好在插入之前获取序列的下一个值,而不是在插入之后获取当前值,因为后者在多线程环境(如任何Web应用程序容器)中可能返回错误的值。JTDS MSSQL驱动程序支持getGeneratedKeys。
(应该澄清,我通常使用Oracle,所以对于JDBC驱动程序的功能有非常低的期望)。
根据我所知,如果您在相同的语句(在同一事务中)中使用它,则不适用于这一点。我IRC Hibernate也是这样工作的。
NOT设置Statement.RETURN_GENERATED_KEYS选项的一个有趣的副作用是错误消息,它是完全模糊的"The statement must be executed before any results can be obtained."(必须在获取任何结果之前执行该语句)。
非常好的帖子。非常有帮助。我只想问一下generatedKeys.next()的用途。为什么close(connection, preparedStatement, generatedKeys)不起作用。为什么需要关闭这三个?谢谢。
generatedKeys.next()返回true,如果数据库返回一个生成的键。注意,这是一个ResultSet。close()只是为了释放资源。否则,您的数据库在长时间运行后将耗尽资源,导致应用程序崩溃。您只需要编写一个自己的实用方法来关闭这些资源。详见这个答案和这个答案。
谢谢你的帮助。如果你在"try"之后立即设置autocommit(false),然后在"finally"中将其设置为true,那么并发线程会有问题吗?我的意思是,如果线程1生成了键"X",即使线程1还没有提交,线程2会生成一个与"X"不同的新键吗?
很棒!谢谢分享。一如既往,Oracle与其他数据库(如IE)不同...
谢谢...你的评论让我省了很多麻烦!我一直在遇到这个该死的错误:P
如果插入中有一个ON DUPLICATE KEY子句,并且存在重复的键,是否有办法得到被重复的id/key?还是我必须自己手动查询?因为没有实际进行新插入,getGeneratedKeys()不会返回。
我正在将GUID插入到数据库表中。rs.getString(1)返回null。我该如何解决这个问题?
很好的答案。我正在寻找在JDBC中插入连接表的解决方案。我在这里有一个详细的帖子,请分享您的经验。
对于大多数数据库/驱动程序来说,这是正确的答案。但是对于Oracle来说,这不起作用。对于Oracle,改为:connection.prepareStatement(sql,new String[] {"PK column name"});
不需要抛出SQLException。
getGeneratedKeys()仅返回一个ROWID列 - Oracle 11.
"最好在插入之前获取序列的下一个值,而不是在插入之后获取当前值"。这是有道理的,但我没有完全理解。我正在尝试使用getGeneratedKeys()获取id。如何获取"插入之前序列的下一个值"?
我认为你的答案比提出的答案更通用。
对于PreparedStatement,应该使用PreparedStatement.RETURN_GENERATED_KEYS而不是Statement.RETURN_GENERATED_KEYS。
不,PreparedStatement扩展了Statement。该常量实际上在Statement中定义。
如果我想获取的属性不是键,有没有办法知道生成的键是由哪个列生成的?ResultSetMetaData#getColumnName只返回"GENERATED_KEYS"。