如何在JDBC中获得插入的ID?

10 浏览
0 Comments

如何在JDBC中获得插入的ID?

我想使用Java中的JDBC在数据库中插入一条记录(在我这种情况下是Microsoft SQL Server)。同时,我想获取插入的ID。如何使用JDBC API实现这一点?

0
0 Comments

在使用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。

0
0 Comments

在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。

0
0 Comments

在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"。

0