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
可以极大地方便我们的编码。