useGeneratedKeys in JDBC编程

发布时间:2023-05-18

JDBC编程中useGeneratedKeys的使用

JDBC编程是Java程序员经常要面对的任务之一。在使用JDBC编程时,我们通常需要往数据库中插入一条新的记录,并需要获取该记录的主键值,以方便我们在之后需要更新或查询该记录时使用。在这种情况下,使用JDBC的useGeneratedKeys选项可以极大地方便我们获取新插入记录的主键值。

一、useGeneratedKeys翻译

useGeneratedKeys表示是否在执行SQL语句时返回自动生成的主键值。

二、useGeneratedKeys没有返回主键

在JDBC3.0及以前的版本中,使用executeUpdate()方式进行插入时,并没有返回该记录的主键值。

String sql = "INSERT INTO users(name,email) VALUES('Tom','tom@example.com')";
Statement stmt = conn.createStatement();
stmt.executeUpdate(sql);
// 以下代码并不能获取本次插入的记录的主键值
ResultSet rs = stmt.getGeneratedKeys();
if(rs.next()) {
    int id = rs.getInt(1);
}

在上述代码中,使用getGeneratedKeys()方法来获取插入记录的主键值,但该方法并不能返回任何结果。

三、useGeneratedKeys的作用

使用useGeneratedKeys的目的是在执行插入操作时,获取该记录的自动生成的主键值。主键值的获取方式因数据库而异。 在MySQL中,通常会使用自增列作为主键,因此可以通过获取自增列的值来获取新插入记录的主键值。

String sql = "INSERT INTO users(name,email) VALUES('Tom','tom@example.com')";
PreparedStatement pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
pstmt.executeUpdate();
// 获取自动生成的主键
ResultSet rs = pstmt.getGeneratedKeys();
if(rs.next()) {
    int id = rs.getInt(1);
}

在上述代码中,使用PreparedStatement预编译SQL语句,并通过Statement.RETURN_GENERATED_KEYS设置返回自动生成的主键。在执行SQL语句后,使用getGeneratedKeys()方法即可获取主键值。 需要注意的是,在使用useGeneratedKeys时,需要保证数据库对该表的主键是自增的。

四、useGeneratedKeys怎么读

useGeneratedKeys的读法为“用斯杰尼雷特基斯”

五、useGeneratedKeys默认值

useGeneratedKeys的默认值为false,即不返回自动生成的主键值。

六、useGeneratedKeys的原理

在执行SQL语句时,如果使用了useGeneratedKeys选项,JDBC会向数据库发送两次SQL语句,第一次执行实际的Insert语句,第二次查询由数据库生成的主键。如果Insert语句导致生成了主键,则会返回单个结果集来包含新生成的主键值,否则返回空结果集。 需要注意的是,使用useGeneratedKeys时,底层数据库驱动程序或JDBC实现可能会有特定的要求,例如特定的游标类型或结果集类型。

七、useGeneratedKeys源码解析

useGeneratedKeys的源码解析可以参考JDK中的java.sql.PreparedStatement接口。在该接口中,executeUpdate()方法的实现为:

boolean execute(String sql, int autoGeneratedKeys) throws SQLException;
boolean execute(String sql, int[] columnIndexes) throws SQLException;
boolean execute(String sql, String[] columnNames) throws SQLException;
default int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException {
    throw new UnsupportedOperationException("executeUpdate not implemented");
}

上述代码中,executeUpdate()方法默认抛出UnsupportedOperationException异常,需要由具体的数据库驱动程序实现。 以MySQL的数据库驱动程序为例,executeUpdate()方法的实现可以参考com.mysql.cj.jdbc.PreparedStatementImpl。在该类中,executeUpdate()方法的实现为:

public int executeUpdate() throws SQLException {
    if (this.connection.isReadOnly()) {
        throw new SQLException(Messages.getString("PreparedStatement.33"));
    } else {
        try {
            if (this.doPingInstead()) {
                return this.rowCount;
            } else {
                this.clearWarnings();
                this.batchedGeneratedKeys = null;
                this.lastInsertId = -1L;
                this.updateCount = -1;
                this.lastUpdateId = -1L;
                if (this.connection.getIO().isOracleMode()) {
                    OraclePreparedStatement var13 = this.getBatchedGeneratedKeys();
                    if (var13 != null) {
                        return var13.executeUpdate();
                    }
                }
                java.sql.PreparedStatement var1 = this.getBatchedGeneratedKeys();
                if (var1 != null) {
                    return var1.executeUpdate();
                } else {
                    java.sql.PreparedStatement var12 = this.prepareStatementForAutoGeneratedKeys(this.getValues().get(0));
                    return var12.executeUpdate();
                }
            }
        } catch (SQLException var11) {
            this.checkClosed();
            throw var11;
        }
    }
}

可以看到,在executeUpdate()方法中,当useGeneratedKeys选项为true时,会先预编译SQL语句,再执行实际的Insert语句,最后查询由数据库生成的主键。

八、useGeneratedKeys true

使用useGeneratedKeys=true可以方便地获取插入记录的自动生成的主键值,但需要注意的是,数据库对该表的主键必须是自增的。

String sql = "INSERT INTO users(name,email) VALUES('Tom','tom@example.com')";
PreparedStatement pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
pstmt.executeUpdate();
// 获取自动生成的主键
ResultSet rs = pstmt.getGeneratedKeys();
if(rs.next()) {
    int id = rs.getInt(1);
}

九、useGeneratedKeys Oracle

在Oracle数据库中,通常使用SEQUENCE作为主键生成器,因此在使用useGeneratedKeys时,需要获取SEQUENCE当前值作为新插入记录的主键值。其实现方式如下:

String sql = "INSERT INTO users(id,name,email) VALUES(seq_users.NEXTVAL,'Tom','tom@example.com')";
PreparedStatement pstmt = conn.prepareStatement(sql, new int[]{1});
pstmt.executeUpdate();
// 获取自动生成的主键
ResultSet rs = pstmt.getGeneratedKeys();
if(rs.next()) {
    int id = rs.getInt(1);
}

需要注意的是,在上述代码中,PreparedStatement的构造函数参数中,传入了一个包含1的整型数组,表示返回该位置列的值,即主键值。 在Oracle数据库中,useGeneratedKeys选项只支持单个主键,不支持联合主键。

十、总结

通过本文对useGeneratedKeys的介绍,我们知道了该选项的作用、用法以及注意事项。在开发中,如果需要获取自动生成的主键值,使用useGeneratedKeys可以极大地方便我们的编码。