我想在数据库中插入一个记录(在我的情况下是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来获得最后生成的密钥。看看这个答案。
其他回答
如果它是一个自动生成的键,那么你可以使用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来获得最后生成的密钥。看看这个答案。
我正在从一个基于jdbc的单线程应用程序中访问Microsoft SQL Server 2008 R2,并在不使用RETURN_GENERATED_KEYS属性或任何PreparedStatement的情况下拉回最后一个ID。看起来是这样的:
private int insertQueryReturnInt(String SQLQy) {
ResultSet generatedKeys = null;
int generatedKey = -1;
try {
Statement statement = conn.createStatement();
statement.execute(SQLQy);
} catch (Exception e) {
errorDescription = "Failed to insert SQL query: " + SQLQy + "( " + e.toString() + ")";
return -1;
}
try {
generatedKey = Integer.parseInt(readOneValue("SELECT @@IDENTITY"));
} catch (Exception e) {
errorDescription = "Failed to get ID of just-inserted SQL query: " + SQLQy + "( " + e.toString() + ")";
return -1;
}
return generatedKey;
}
这篇博文很好地分离了三个主要的SQL Server“最后ID”选项: http://msjawahar.wordpress.com/2008/01/25/how-to-find-the-last-identity-value-inserted-in-the-sql-server/ -还不需要其他两个。
我正在使用SQLServer 2008,但我有一个开发限制:我不能为它使用一个新的驱动程序,我必须使用“com.microsoft.jdbc.sqlserver”。SQLServerDriver”(我不能使用“com.microsoft.sqlserver.jdbc.SQLServerDriver”)。
这就是为什么解决方案conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)为我抛出了一个java.lang.AbstractMethodError。 在这种情况下,我找到了一个可能的解决方案,即微软提出的旧方案: 如何检索@@IDENTITY值使用JDBC
import java.sql.*;
import java.io.*;
public class IdentitySample
{
public static void main(String args[])
{
try
{
String URL = "jdbc:microsoft:sqlserver://yourServer:1433;databasename=pubs";
String userName = "yourUser";
String password = "yourPassword";
System.out.println( "Trying to connect to: " + URL);
//Register JDBC Driver
Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver").newInstance();
//Connect to SQL Server
Connection con = null;
con = DriverManager.getConnection(URL,userName,password);
System.out.println("Successfully connected to server");
//Create statement and Execute using either a stored procecure or batch statement
CallableStatement callstmt = null;
callstmt = con.prepareCall("INSERT INTO myIdentTable (col2) VALUES (?);SELECT @@IDENTITY");
callstmt.setString(1, "testInputBatch");
System.out.println("Batch statement successfully executed");
callstmt.execute();
int iUpdCount = callstmt.getUpdateCount();
boolean bMoreResults = true;
ResultSet rs = null;
int myIdentVal = -1; //to store the @@IDENTITY
//While there are still more results or update counts
//available, continue processing resultsets
while (bMoreResults || iUpdCount!=-1)
{
//NOTE: in order for output parameters to be available,
//all resultsets must be processed
rs = callstmt.getResultSet();
//if rs is not null, we know we can get the results from the SELECT @@IDENTITY
if (rs != null)
{
rs.next();
myIdentVal = rs.getInt(1);
}
//Do something with the results here (not shown)
//get the next resultset, if there is one
//this call also implicitly closes the previously obtained ResultSet
bMoreResults = callstmt.getMoreResults();
iUpdCount = callstmt.getUpdateCount();
}
System.out.println( "@@IDENTITY is: " + myIdentVal);
//Close statement and connection
callstmt.close();
con.close();
}
catch (Exception ex)
{
ex.printStackTrace();
}
try
{
System.out.println("Press any key to quit...");
System.in.read();
}
catch (Exception e)
{
}
}
}
这个方法对我很有效!
我希望这能有所帮助!
大多数人都建议使用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。
推荐文章
- 为什么历史上人们使用255而不是256作为数据库字段大小?
- 如何选择记录从过去24小时使用SQL?
- 将所有非字母数字字符替换为空字符串
- 如何为查询返回的每一行执行存储过程一次?
- 按IN值列表排序
- 漂亮地打印Java集合(toString不返回漂亮输出)
- 静态嵌套类在Java,为什么?
- 如何防止Eclipse在启动时挂起?
- Optional和Optional的区别是什么?flatMap和Optional.map?
- Java中枚举的命名:单数还是复数?
- 如何使用SQL Server 2008做多个CASE WHEN条件?
- 计数在VARCHAR字段中字符串的出现次数?
- 如何选择多行填充常量?
- 修改一个MySQL列为AUTO_INCREMENT
- 如果没有使用EXISTS引入子查询,则只能在选择列表中指定一个表达式