我想在数据库中插入一个记录(在我的情况下是Microsoft SQL Server)使用Java中的JDBC。同时,我想获取插入ID。我如何使用JDBC API实现这一点?
当前回答
如果它是一个自动生成的键,那么你可以使用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来获得最后生成的密钥。看看这个答案。
其他回答
使用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时遇到“不支持的功能”错误。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。
您可以使用以下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);
}
推荐文章
- 比较两个SQL Server数据库(模式和数据)的最佳工具是什么?
- 如何在java中格式化持续时间?(如格式H:MM:SS)
- 在SQL中,如何在范围中“分组”?
- urlencoder .encode(字符串)已弃用,我应该使用什么代替?
- javax.transaction.Transactional vs . org.springframework.transaction.annotation.Transactional
- Java 8接口方法中不允许“同步”的原因是什么?
- 选项(RECOMPILE)总是更快;为什么?
- 设置数据库从单用户模式到多用户
- 如何找到Java堆大小和内存使用(Linux)?
- oracle中的RANK()和DENSE_RANK()函数有什么区别?
- 的类型不能用作索引中的键列
- SQL逻辑运算符优先级:And和Or
- 使用Enum实现单例(Java)
- 如何检查一个表是否存在于给定的模式中
- RabbitMQ与通道和连接之间的关系