有没有办法从准备好的语句中检索自动增量 ID

Posted

技术标签:

【中文标题】有没有办法从准备好的语句中检索自动增量 ID【英文标题】:Is there a way to retrieve the autoincrement ID from a prepared statement 【发布时间】:2010-11-25 11:05:20 【问题描述】:

在使用带有准备好的语句的 java 查询时,有没有办法从数据库查询中检索自动生成的密钥。

例如,我知道 AutoGeneratedKeys 可以按如下方式工作。

stmt = conn.createStatement();

stmt.executeUpdate(sql, Statement.RETURN_GENERATED_KEYS);
if(returnLastInsertId) 
    ResultSet rs = stmt.getGeneratedKeys();
    rs.next();
    auto_id = rs.getInt(1);
 

但是。如果我想用准备好的语句进行插入怎么办。

String sql = "INSERT INTO table (column1, column2) values(?, ?)";
stmt = conn.prepareStatement(sql);

//this is an error
stmt.executeUpdate(Statement.RETURN_GENERATED_KEYS);
if(returnLastInsertId) 
    //this is an error since the above is an error
    ResultSet rs = stmt.getGeneratedKeys();
    rs.next();
    auto_id = rs.getInt(1);
 

有没有办法做到这一点,我不知道。从 javadoc 看来 PreparedStatements 无法返回自动生成的 ID。

【问题讨论】:

returnLastInsertId 你从哪里得到这个变量 【参考方案1】:

是的。见here。第 7.1.9 节。将您的代码更改为:

String sql = "INSERT INTO table (column1, column2) values(?, ?)";
stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);


stmt.executeUpdate();
if(returnLastInsertId) 
   ResultSet rs = stmt.getGeneratedKeys();
    rs.next();
   auto_id = rs.getInt(1);

【讨论】:

@JafarAli,这个问题是关于 mysql 的。在 oracle 中,您必须指定 the generated column 或使用行 ID。 你忘记rs.close()了吗?有必要吗? @Winter,这段代码专注于解决问题中的问题,而不是处理资源和异常处理。像任何其他语句和结果集一样,调用 close 是必要的。 @Winter,如果你的键是长的,那么在最后调用 rs.getLong(1)。【参考方案2】:

有几种方法,似乎不同的 jdbc 驱动程序处理事情有点不同,或者在某些情况下根本没有(有些只会给你自动生成的主键,而不是其他列),但基本形式是

stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); 

或者使用这种形式:

String autogenColumns[] = "column1","column2";
stmt = conn.prepareStatement(sql, autogenColumns)

【讨论】:

【参考方案3】:

是的,有办法。我刚刚发现它隐藏在 java doc 中。

他们的方式是传递 AutoGeneratedKeys id 如下

String sql = "INSERT INTO table (column1, column2) values(?, ?)";
stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);

【讨论】:

【参考方案4】:

我是那些浏览了几个线程以寻找此问题的解决方案的人之一......并最终让它发挥作用。对于那些使用 jdbc:oracle:thin: 和 ojdbc6.jar 请注意: 您可以使用任何一种方法: (方法一)

Try
    String yourSQL="insert into Table1(Id,Col2,Col3) values(SEQ.nextval,?,?)";
    myPrepStatement = <Connection>.prepareStatement(yourSQL, Statement.RETURN_GENERATED_KEYS);
    myPrepStatement.setInt(1, 123); 
    myPrepStatement.setInt(2, 123); 

    myPrepStatement.executeUpdate();
    ResultSet rs = getGeneratedKeys;
    if(rs.next()) 
      java.sql.RowId rid=rs.getRowId(1); 
      //what you get is only a RowId ref, try make use of it anyway U could think of
      System.out.println(rid);
    
 catch (SQLException e) 
  //

(方法二)

Try
    String yourSQL="insert into Table1(Id,Col2,Col3) values(SEQ.nextval,?,?)";
    //IMPORTANT: here's where other threads don tell U, you need to list ALL cols 
    //mentioned in your query in the array
    myPrepStatement = <Connection>.prepareStatement(yourSQL, new String[]"Id","Col2","Col3");
    myPrepStatement.setInt(1, 123); 
    myPrepStatement.setInt(2, 123); 
    myPrepStatement.executeUpdate();
    ResultSet rs = getGeneratedKeys;
    if(rs.next()) 
    //In this exp, the autoKey val is in 1st col
    int id=rs.getLong(1);
    //now this's a real value of col Id
    System.out.println(id);
    
 catch (SQLException e) 
  //

基本上,如果您只想要 SEQ.Nextval 的值,请尽量不要使用 Method1,b'cse 它只是返回 RowID ref,您可能会想方设法使用它,它也不适合所有数据类型您尝试将其投射到!这在 MySQL、DB2 中可能工作正常(返回实际 val),但在 Oracle 中不行。

并且,在调试时关闭 SQL Developer、Toad 或任何使用相同登录会话执行 INSERT 的客户端。它可能不会每次都影响你(调试调用)......直到你发现你的应用程序无一例外地冻结了一段时间。是的……毫无例外地停止!

【讨论】:

executeUpdate() 不返回ResultSet,而是返回int,即更新计数。您必须单独检索生成的密钥。请参阅现有答案,以及看在上帝的份上的 Javadoc。 -1。 Again. 请不要在这里发布您未经测试的猜测。【参考方案5】:
    Connection connection=null;
    int generatedkey=0;
    PreparedStatement pstmt=connection.prepareStatement("Your insert query");
    ResultSet rs=pstmt.getGeneratedKeys();
    if (rs.next()) 
       generatedkey=rs.getInt(1);   
               System.out.println("Auto Generated Primary Key " + generatedkey); 
    

【讨论】:

以上是关于有没有办法从准备好的语句中检索自动增量 ID的主要内容,如果未能解决你的问题,请参考以下文章

从 PDO 准备语句中检索(或模拟)完整查询

从 PDO 准备好的语句中获取查询 [重复]

从 PDO 准备好的语句中获取原始 SQL 查询字符串

从 PDO 准备好的语句中获取原始 SQL 查询字符串

Spring JPA - 准备好的语句查询?

如何列出所有活动会话的所有准备好的语句?