[英]How to get the insert ID in JDBC?
I want to INSERT
a record in a database (which is Microsoft SQL Server in my case) using JDBC in Java.我想在 Java 中使用 JDBC 在数据库中
INSERT
一条记录(在我的例子中是 Microsoft SQL 服务器)。 At the same time, I want to obtain the insert ID.同时,我想获取插入ID。 How can I achieve this using JDBC API?
如何使用 JDBC API 实现此目的?
If it is an auto generated key, then you can use Statement#getGeneratedKeys()
for this.如果它是自动生成的密钥,那么您可以为此使用
Statement#getGeneratedKeys()
。 You need to call it on the same Statement
as the one being used for the INSERT
.您需要在与用于
INSERT
Statement
相同的Statement
上调用它。 You first need to create the statement using Statement.RETURN_GENERATED_KEYS
to notify the JDBC driver to return the keys.您首先需要使用
Statement.RETURN_GENERATED_KEYS
创建Statement.RETURN_GENERATED_KEYS
以通知 JDBC 驱动程序返回密钥。
Here's a basic example:这是一个基本示例:
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.");
}
}
}
}
Note that you're dependent on the JDBC driver as to whether it works.请注意,您依赖于 JDBC 驱动程序是否工作。 Currently, most of the last versions will work, but if I am correct, Oracle JDBC driver is still somewhat troublesome with this.
目前,大多数最新版本都可以工作,但如果我是对的,Oracle JDBC 驱动程序在这方面仍然有些麻烦。 MySQL and DB2 already supported it for ages.
MySQL 和 DB2 已经支持它很久了。 PostgreSQL started to support it not long ago.
PostgreSQL 不久前开始支持它。 I can't comment about MSSQL as I've never used it.
我无法评论 MSSQL,因为我从未使用过它。
For Oracle, you can invoke a CallableStatement
with a RETURNING
clause or a SELECT CURRVAL(sequencename)
(or whatever DB-specific syntax to do so) directly after the INSERT
in the same transaction to obtain the last generated key.对于 Oracle,您可以在同一事务中的
INSERT
之后直接CallableStatement
带有RETURNING
子句或SELECT CURRVAL(sequencename)
(或任何特定于数据库的语法SELECT CURRVAL(sequencename)
的CallableStatement
以获取最后生成的键。 See also this answer .另请参阅此答案。
Create Generated Column创建生成的列
String generatedColumns[] = { "ID" };
Pass this geneated Column to your statement将此生成的 Column 传递给您的语句
PreparedStatement stmtInsert = conn.prepareStatement(insertSQL, generatedColumns);
Use ResultSet
object to fetch the GeneratedKeys on Statement使用
ResultSet
对象在 Statement 上获取 GeneratedKeys
ResultSet rs = stmtInsert.getGeneratedKeys(); if (rs.next()) { long id = rs.getLong(1); System.out.println("Inserted ID -" + id); // display inserted record }
When encountering an 'Unsupported feature' error while using Statement.RETURN_GENERATED_KEYS
, try this:在使用
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();
}
Where BATCHID
is the auto generated id.其中
BATCHID
是自动生成的 ID。
I'm hitting Microsoft SQL Server 2008 R2 from a single-threaded JDBC-based application and pulling back the last ID without using the RETURN_GENERATED_KEYS property or any PreparedStatement.我正在从基于单线程 JDBC 的应用程序访问 Microsoft SQL Server 2008 R2,并在不使用 RETURN_GENERATED_KEYS 属性或任何 PreparedStatement 的情况下拉回最后一个 ID。 Looks something like this:
看起来像这样:
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;
}
This blog post nicely isolates three main SQL Server "last ID" options: http://msjawahar.wordpress.com/2008/01/25/how-to-find-the-last-identity-value-inserted-in-the-sql-server/ - haven't needed the other two yet.这篇博文很好地隔离了三个主要的 SQL Server“最后一个 ID”选项: http : //msjawahar.wordpress.com/2008/01/25/how-to-find-the-last-identity-value-inserted-in-the -sql-server/ - 还不需要另外两个。
Instead of a comment , I just want to answer post.而不是评论,我只想回答帖子。
Interface java.sql.PreparedStatement接口java.sql.PreparedStatement
columnIndexes « You can use prepareStatement function that accepts columnIndexes and SQL statement. columnIndexes « 您可以使用接受 columnIndexes 和 SQL 语句的 prepareStatement 函数。 Where columnIndexes allowed constant flags are Statement.RETURN_GENERATED_KEYS 1 or Statement.NO_GENERATED_KEYS[2], SQL statement that may contain one or more '?'
其中 columnIndexes 允许的常量标志是 Statement.RETURN_GENERATED_KEYS 1或 Statement.NO_GENERATED_KEYS[2],SQL 语句可能包含一个或多个 '?' IN parameter placeholders.
IN 参数占位符。
SYNTAX «句法 ”
Connection.prepareStatement(String sql, int autoGeneratedKeys) Connection.prepareStatement(String sql, int[] columnIndexes)
Example:例子:
PreparedStatement pstmt = conn.prepareStatement( insertSQL, Statement.RETURN_GENERATED_KEYS );
columnNames « List out the columnNames like 'id', 'uniqueID', ...
. columnNames «列出 columnNames,如
'id', 'uniqueID', ...
。 in the target table that contain the auto-generated keys that should be returned.在包含应返回的自动生成的键的目标表中。 The driver will ignore them if the SQL statement is not an
INSERT
statement.如果 SQL 语句不是
INSERT
语句,驱动程序将忽略它们。
SYNTAX «句法 ”
Connection.prepareStatement(String sql, String[] columnNames)
Example:例子:
String columnNames[] = new String[] { "id" }; PreparedStatement pstmt = conn.prepareStatement( insertSQL, columnNames );
Full Example:完整示例:
public static void insertAutoIncrement_SQL(String UserName, String Language, String Message) {
String DB_URL = "jdbc:mysql://localhost:3306/test", DB_User = "root", DB_Password = "";
String insertSQL = "INSERT INTO `unicodeinfo`( `UserName`, `Language`, `Message`) VALUES (?,?,?)";
//"INSERT INTO `unicodeinfo`(`id`, `UserName`, `Language`, `Message`) VALUES (?,?,?,?)";
int primkey = 0 ;
try {
Class.forName("com.mysql.jdbc.Driver").newInstance();
Connection conn = DriverManager.getConnection(DB_URL, DB_User, DB_Password);
String columnNames[] = new String[] { "id" };
PreparedStatement pstmt = conn.prepareStatement( insertSQL, columnNames );
pstmt.setString(1, UserName );
pstmt.setString(2, Language );
pstmt.setString(3, Message );
if (pstmt.executeUpdate() > 0) {
// Retrieves any auto-generated keys created as a result of executing this Statement object
java.sql.ResultSet generatedKeys = pstmt.getGeneratedKeys();
if ( generatedKeys.next() ) {
primkey = generatedKeys.getInt(1);
}
}
System.out.println("Record updated with id = "+primkey);
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
}
I'm using SQLServer 2008, but I have a development limitation: I cannot use a new driver for it, I have to use "com.microsoft.jdbc.sqlserver.SQLServerDriver" (I cannot use "com.microsoft.sqlserver.jdbc.SQLServerDriver").我正在使用SQLServer 2008,但我有一个开发限制:我不能使用新的驱动程序,我必须使用“com.microsoft.jdbc.sqlserver.SQLServerDriver”(我不能使用“com.microsoft.sqlserver.jdbc .SQLServerDriver”)。
That's why the solution conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)
threw a java.lang.AbstractMethodError for me.这就是解决方案
conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)
为我抛出java.lang.AbstractMethodError的原因。 In this situation, a possible solution I found is the old one suggested by Microsoft: How To Retrieve @@IDENTITY Value Using JDBC在这种情况下,我发现一个可能的解决方案是 Microsoft 建议的旧解决方案: How To Retrieve @@IDENTITY Value Using 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)
{
}
}
}
This solution worked for me!这个解决方案对我有用!
I hope this helps!我希望这有帮助!
You can use following java code to get new inserted 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);
}
It is possible to use it with normal Statement
's as well (not just PreparedStatement
)也可以将它与普通
Statement
一起使用(不仅仅是PreparedStatement
)
Statement statement = conn.createStatement();
int updateCount = statement.executeUpdate("insert into x...)", Statement.RETURN_GENERATED_KEYS);
try (ResultSet generatedKeys = statement.getGeneratedKeys()) {
if (generatedKeys.next()) {
return generatedKeys.getLong(1);
}
else {
throw new SQLException("Creating failed, no ID obtained.");
}
}
With Hibernate's NativeQuery, you need to return a ResultList instead of a SingleResult, because Hibernate modifies a native query使用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
if you try to get a single result, which causes most databases (at least PostgreSQL) to throw a syntax error.如果您尝试获得单个结果,这会导致大多数数据库(至少是 PostgreSQL)抛出语法错误。 Afterwards, you may fetch the resulting id from the list (which usually contains exactly one item).
之后,您可以从列表中获取结果 id(通常只包含一个项目)。
In my case ->就我而言->
ConnectionClass objConnectionClass=new ConnectionClass();
con=objConnectionClass.getDataBaseConnection();
pstmtGetAdd=con.prepareStatement(SQL_INSERT_ADDRESS_QUERY,Statement.RETURN_GENERATED_KEYS);
pstmtGetAdd.setString(1, objRegisterVO.getAddress());
pstmtGetAdd.setInt(2, Integer.parseInt(objRegisterVO.getCityId()));
int addId=pstmtGetAdd.executeUpdate();
if(addId>0)
{
ResultSet rsVal=pstmtGetAdd.getGeneratedKeys();
rsVal.next();
addId=rsVal.getInt(1);
}
If you are using Spring JDBC, you can use Spring's GeneratedKeyHolder class to get the inserted ID.如果您使用的是 Spring JDBC,则可以使用 Spring 的 GeneratedKeyHolder 类来获取插入的 ID。
See this answer... How to get inserted id using Spring Jdbctemplate.update(String sql, obj...args)请参阅此答案... 如何使用 Spring Jdbctemplate.update(String sql, obj...args) 获取插入的 id
If you are using JDBC (tested with MySQL) and you just want the last inserted ID, there is an easy way to get it.如果您使用的是 JDBC(用 MySQL 测试)并且您只想要最后插入的 ID,那么有一个简单的方法来获取它。 The method I'm using is the following:
我正在使用的方法如下:
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;
}
Also, (and just in case) the method to get the ConnectionImpl
is the following:此外,(以防万一)获取
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;
}
Remember to add the connector/J to the project referenced libraries.请记住将连接器/J添加到项目引用的库中。
In my case, the connector/J version is the 5.1.42.就我而言,连接器/J 版本是 5.1.42。 Maybe you will have to apply some changes to the
connectionPath
if you want to use a more modern version of the connector/J such as with the version 8.0.28.如果您想使用更现代的连接器/J 版本(例如版本 8.0.28),您可能必须对
connectionPath
应用一些更改。
In the file, remember to import the following resources:在文件中,记得导入以下资源:
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import com.mysql.jdbc.ConnectionImpl;
Hope this will be helpful.希望这会有所帮助。
Most others have suggested to use JDBC API for this, but personally, I find it quite painful to do with most drivers.大多数其他人都建议为此使用 JDBC API ,但就个人而言,我发现大多数驱动程序都非常痛苦。 When in fact, you can just use a native T-SQL feature, the
OUTPUT
clause :事实上,您可以只使用本机 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));
}
This is the simplest solution for SQL Server as well as a few other SQL dialects (eg Firebird, MariaDB, PostgreSQL, where you'd use RETURNING
instead of OUTPUT
). This is the simplest solution for SQL Server as well as a few other SQL dialects (eg Firebird, MariaDB, PostgreSQL, where you'd use
RETURNING
instead of OUTPUT
).
I've blogged about this topic more in detail here . 我在这里更详细地讨论了这个主题。
Connection cn = DriverManager.getConnection("Host","user","pass");
Statement st = cn.createStatement("Ur Requet Sql");
int ret = st.execute();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.