如何在JDBC中获取插入ID?

时间:2009-12-16 14:57:58

标签: java sql jdbc insert-id

我想在Java中使用JDBC中的INSERT数据库(在我的情况下是Microsoft SQL Server)中的记录。同时,我想获取插入ID。如何使用JDBC API实现此目的?

12 个答案:

答案 0 :(得分:602)

如果是自动生成的密钥,则可以使用Statement#getGeneratedKeys()。您需要在与Statement使用的INSERT相同的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."); } } } } 上调用它。您首先需要使用Statement.RETURN_GENERATED_KEYS创建语句,以通知JDBC驱动程序返回密钥。

这是一个基本的例子:

CallableStatement

请注意,您是否依赖JDBC驱动程序来确定它是否有效。目前,大多数最新版本都可以使用,但如果我是正确的,Oracle JDBC驱动程序仍然有点麻烦。 MySQL和DB2已经支持它多年了。不久前PostgreSQL开始支持它。我无法评论MSSQL,因为我从未使用它。

对于Oracle,您可以在RETURNING之后直接调用SELECT CURRVAL(sequencename) INSERT子句或{{1}}(或任何特定于DB的语法)。获取最后生成的密钥的相同事务。另请参阅this answer

答案 1 :(得分:14)

  1. 创建生成列

    String generatedColumns[] = { "ID" };
    
  2. 将此生成的列传递给您的陈述

    PreparedStatement stmtInsert = conn.prepareStatement(insertSQL, generatedColumns);
    
  3. 使用ResultSet对象获取Statement

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

答案 2 :(得分:8)

我从单线程基于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/ - 尚未需要其他两个。

答案 3 :(得分:5)

根据'不支持的功能'使用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();

    }

BRANCHID是自动生成的ID

答案 4 :(得分:3)

我正在使用 SQLServer 2008,但我有一个开发限制:我不能使用新的驱动程序,我必须使用“com.microsoft.jdbc.sqlserver.SQLServerDriver”(我不能使用“com.microsoft.sqlserver.jdbc.SQLServerDriver”)。

这就是解决方案conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)为我提出 java.lang.AbstractMethodError 的原因。 在这种情况下,我发现的一个可能的解决方案是微软建议的旧解决方案: 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)
        {
        }
    }
}

这个解决方案对我有用!

我希望这有帮助!

答案 5 :(得分:1)

您可以使用以下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);
                }

答案 6 :(得分:0)

而不是comment,我只想回答帖子。

界面 java.sql.PreparedStatement

  1. columnIndexes «您可以使用接受columnIndexes和SQL语句的prepareStatement函数。 其中columnIndexes允许的常量标志是Statement.RETURN_GENERATED_KEYS 1或Statement.NO_GENERATED_KEYS [2],SQL语句可能包含一个或多个'?' IN参数占位符。

    语法«

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

    示例:

    PreparedStatement pstmt = 
        conn.prepareStatement( insertSQL, Statement.RETURN_GENERATED_KEYS );
    
    1. columnNames «列出像'id', 'uniqueID', ...这样的columnNames。在目标表中包含应返回的自动生成的键。如果SQL语句不是INSERT语句,则驱动程序将忽略它们。

      语法«

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

      示例:

      String columnNames[] = new String[] { "id" };
      PreparedStatement pstmt = conn.prepareStatement( insertSQL, columnNames );
      
    2. 完整示例:

      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 :(得分:0)

使用Hibernate的NativeQuery,您需要返回ResultList而不是SingleResult,因为Hibernate会修改本机查询

INSERT INTO bla (a,b) VALUES (2,3) RETURNING id

INSERT INTO bla (a,b) VALUES (2,3) RETURNING id LIMIT 1

如果您尝试获得单个结果,这会导致大多数数据库(至少PostgreSQL)抛出语法错误。之后,您可以从列表中获取结果ID(通常只包含一个项目)。

答案 8 :(得分:0)

也可以将其与普通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.");
  }
}

答案 9 :(得分:0)

就我而言->

29-08-2018

答案 10 :(得分:0)

如果使用的是Spring JDBC,则可以使用Spring的GeneratedKeyHolder类获取插入的ID。

查看此答案... How to get inserted id using Spring Jdbctemplate.update(String sql, obj...args)

答案 11 :(得分:-5)

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