How to get the insert ID in JDBC?

JavaSqlJdbcInsert Id

Java Problem Overview


I want to INSERT a record in a database (which is Microsoft SQL Server in my case) using JDBC in Java. At the same time, I want to obtain the insert ID. How can I achieve this using JDBC API?

Java Solutions


Solution 1 - Java

If it is an auto generated key, then you can use Statement#getGeneratedKeys() for this. You need to call it on the same Statement as the one being used for the INSERT. You first need to create the statement using Statement.RETURN_GENERATED_KEYS to notify the JDBC driver to return the keys.

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. Currently, most of the last versions will work, but if I am correct, Oracle JDBC driver is still somewhat troublesome with this. MySQL and DB2 already supported it for ages. PostgreSQL started to support it not long ago. I can't comment about MSSQL as I've never used it.

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. See also this answer.

Solution 2 - Java

  1. Create Generated Column

     String generatedColumns[] = { "ID" };
    
  2. Pass this geneated Column to your statement

     PreparedStatement stmtInsert = conn.prepareStatement(insertSQL, generatedColumns);
    
  3. Use ResultSet object to fetch the GeneratedKeys on Statement

     ResultSet rs = stmtInsert.getGeneratedKeys();
    
     if (rs.next()) {
         long id = rs.getLong(1);
         System.out.println("Inserted ID -" + id); // display inserted record
     }
    

Solution 3 - Java

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. 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.

Solution 4 - Java

When encountering an 'Unsupported feature' error while using Statement.RETURN_GENERATED_KEYS, try this:

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.

Solution 5 - Java

Instead of a comment, I just want to answer post.


Interface java.sql.PreparedStatement

  1. columnIndexes « You can use prepareStatement function that accepts columnIndexes and SQL statement. Where columnIndexes allowed constant flags are Statement.RETURN_GENERATED_KEYS1 or Statement.NO_GENERATED_KEYS[2], SQL statement that may contain one or more '?' IN parameter placeholders.

SYNTAX «

	Connection.prepareStatement(String sql, int autoGeneratedKeys)
	Connection.prepareStatement(String sql, int[] columnIndexes)

<!-- language-all: lang-java -->

Example:

<!-- language-all: lang-java -->

	PreparedStatement pstmt = 
		conn.prepareStatement( insertSQL, Statement.RETURN_GENERATED_KEYS );

<!-- language-all: lang-java -->

  1. columnNames « List out the columnNames like '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.

SYNTAX «

<!-- language-all: lang-java -->

	Connection.prepareStatement(String sql, String[] columnNames)

<!-- language-all: lang-java -->

Example:

<!-- language-all: lang-java -->
	
	String columnNames[] = new String[] { "id" };
	PreparedStatement pstmt = conn.prepareStatement( insertSQL, columnNames );
	
<!-- language-all: lang-java -->

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();
	}
}

Solution 6 - Java

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").

That's why the solution conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS) threw a java.lang.AbstractMethodError for me. In this situation, a possible solution I found is the old one suggested by 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!

Solution 7 - Java

You can use following java code to get new inserted 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);
}

Solution 8 - Java

It is possible to use it with normal Statement's as well (not just 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.");
  }
}

Solution 9 - Java

With Hibernate's NativeQuery, you need to return a ResultList instead of a SingleResult, because Hibernate modifies a native query

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. Afterwards, you may fetch the resulting id from the list (which usually contains exactly one item).

Solution 10 - Java

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);
}

Solution 11 - Java

If you are using Spring JDBC, you can use Spring's GeneratedKeyHolder class to get the inserted ID.

See this answer... https://stackoverflow.com/questions/35088885/how-to-get-inserted-id-using-spring-jdbctemplate-updatestring-sql-obj-args

Solution 12 - Java

If you are using JDBC (tested with MySQL) and you just want the last inserted ID, there is an easy way to get it. 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:

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.

In my case, the connector/J version is the 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.

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.

Solution 13 - Java

Connection cn = DriverManager.getConnection("Host","user","pass");
Statement st = cn.createStatement("Ur Requet Sql");
int ret  = st.execute();

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSatyaView Question on Stackoverflow
Solution 1 - JavaBalusCView Answer on Stackoverflow
Solution 2 - JavaHarsh MaheswariView Answer on Stackoverflow
Solution 3 - JavaftexpertsView Answer on Stackoverflow
Solution 4 - JavaEitan RimonView Answer on Stackoverflow
Solution 5 - JavaYashView Answer on Stackoverflow
Solution 6 - JavaxanblaxView Answer on Stackoverflow
Solution 7 - Javauser11533210View Answer on Stackoverflow
Solution 8 - JavarogerdpackView Answer on Stackoverflow
Solution 9 - JavaBalinView Answer on Stackoverflow
Solution 10 - JavaTheSagyaView Answer on Stackoverflow
Solution 11 - JavaRob BreideckerView Answer on Stackoverflow
Solution 12 - JavaPolView Answer on Stackoverflow
Solution 13 - JavaAbdelkhalek BenhoumineView Answer on Stackoverflow