我想在数据库中插入一个记录(在我的情况下是Microsoft SQL Server)使用Java中的JDBC。同时,我想获取插入ID。我如何使用JDBC API实现这一点?
当前回答
您可以使用以下java代码来获取新的插入id。
ps = con.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
ps.setInt(1, quizid);
ps.setInt(2, userid);
ps.executeUpdate();
ResultSet rs = ps.getGeneratedKeys();
if (rs.next()) {
lastInsertId = rs.getInt(1);
}
其他回答
当使用Statement时遇到“不支持的功能”错误。RETURN_GENERATED_KEYS,试试这个:
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。
使用Hibernate的NativeQuery,您需要返回一个ResultList而不是SingleResult,因为Hibernate修改了一个本机查询
INSERT INTO bla (a,b) VALUES (2,3) RETURNING id
like
INSERT INTO bla (a,b) VALUES (2,3) RETURNING id LIMIT 1
如果你试图得到一个单一的结果,这将导致大多数数据库(至少PostgreSQL)抛出一个语法错误。然后,您可以从列表中获取结果id(通常只包含一个项)。
如果您正在使用JDBC(用MySQL测试),并且只想要最后插入的ID,有一种简单的方法可以获得它。我使用的方法如下:
public static Integer insert(ConnectionImpl connection, String insertQuery){
Integer lastInsertId = -1;
try{
final PreparedStatement ps = connection.prepareStatement(insertQuery);
ps.executeUpdate(insertQuery);
final com.mysql.jdbc.PreparedStatement psFinal = (com.mysql.jdbc.PreparedStatement) ps;
lastInsertId = (int) psFinal.getLastInsertID();
connection.close();
} catch(SQLException ex){
System.err.println("Error: "+ex);
}
return lastInsertId;
}
同样,(以防万一)获取ConnectionImpl的方法如下:
public static ConnectionImpl getConnectionImpl(){
ConnectionImpl conexion = null;
final String dbName = "database_name";
final String dbPort = "3306";
final String dbIPAddress = "127.0.0.1";
final String connectionPath = "jdbc:mysql://"+dbIPAddress+":"+dbPort+"/"+dbName+"?autoReconnect=true&useSSL=false";
final String dbUser = "database_user";
final String dbPassword = "database_password";
try{
conexion = (ConnectionImpl) DriverManager.getConnection(connectionPath, dbUser, dbPassword);
}catch(SQLException e){
System.err.println(e);
}
return conexion;
}
记得将连接器/J添加到项目引用的库中。
在我的例子中,连接器/J版本是5.1.42。如果您想使用连接器/J的更现代的版本,例如8.0.28版本,那么您可能必须对connectionPath应用一些更改。
在文件中,请记住导入以下资源:
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import com.mysql.jdbc.ConnectionImpl;
希望这对你有所帮助。
大多数人都建议使用JDBC API来实现这一点,但就我个人而言,我发现使用大多数驱动程序是非常痛苦的。实际上,你可以使用一个原生的T-SQL特性,OUTPUT子句:
try (
Statement s = c.createStatement();
ResultSet rs = s.executeQuery(
"""
INSERT INTO t (a, b)
OUTPUT id
VALUES (1, 2)
"""
);
) {
while (rs.next())
System.out.println("ID = " + rs.getLong(1));
}
这是SQL Server以及其他一些SQL方言的最简单的解决方案(例如,Firebird, MariaDB, PostgreSQL,其中您将使用返回而不是输出)。
关于这个话题,我已经在这里写过更详细的博客。
如果它是一个自动生成的键,那么你可以使用Statement#getGeneratedKeys()。您需要在与INSERT使用的语句相同的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子句或SELECT CURRVAL(sequencename)(或任何特定于db的语法)的CallableStatement来获得最后生成的密钥。看看这个答案。
推荐文章
- 对于PostgreSQL表来说,多大才算太大?
- 等待未来的名单
- 如何检查JSON键是否存在?
- 为什么MongoDB Java驱动在条件中使用随机数生成器?
- 即使从未抛出异常,使用try-catch块的代价是否昂贵?
- 什么时候我们应该使用观察者和可观察对象?
- Java中的split()方法对点(.)不起作用。
- Eclipse调试器总是阻塞在ThreadPoolExecutor上,没有任何明显的异常,为什么?
- Java生成两个给定值之间的随机数
- 在MySQL中检测值是否为number
- 如何有效地从数组列表或字符串数组中删除所有空元素?
- MySQL中两个日期之间的差异
- 比较JUnit断言中的数组,简洁的内置方式?
- codestyle;把javadoc放在注释之前还是之后?
- 如何在Spring中定义List bean ?