How to get the insert ID in JDBC?

送分小仙女□ 提交于 2019-11-25 21:43:32

问题


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?


回答1:


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.




回答2:


  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
    }
    



回答3:


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.




回答4:


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.




回答5:


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!




回答6:


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)
    

    Example:

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

  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 «

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



回答7:


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




回答8:


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



回答9:


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



回答10:


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

See this answer... How to get inserted id using Spring Jdbctemplate.update(String sql, obj...args)




回答11:


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



回答12:


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


来源:https://stackoverflow.com/questions/1915166/how-to-get-the-insert-id-in-jdbc

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!