How to get the insert ID in JDBC?

后端 未结 12 1711
暖寄归人
暖寄归人 2020-11-21 06:09

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

相关标签:
12条回答
  • 2020-11-21 06:25
    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
      }
      
    0 讨论(0)
  • 2020-11-21 06:25

    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.

    0 讨论(0)
  • 2020-11-21 06:25

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

    0 讨论(0)
  • 2020-11-21 06:28

    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.

    0 讨论(0)
  • 2020-11-21 06:34

    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();
        }
    }
    
    0 讨论(0)
  • 2020-11-21 06:35

    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.

    0 讨论(0)
提交回复
热议问题