2014-11-22 65 views
5

我的問題是我想要做JDBC批量插入和檢索標識列的值。 MS SQL驅動程序不支持此功能。任何人都可以指導我如何解決這個問題?JDBC驅動程序不支持通過檢索標識列進行批量更新。爲什麼?

+1

您是否嘗試過使用['Statement#getGeneratedKeys'](https://docs.oracle.com/javase/8/docs/api/java/sql/Statement.html#getGeneratedKeys--)? – 2014-11-22 15:32:27

+2

明顯的解決方案:不要使用批量插入,而是在循環中用'getGeneratedKeys'完成正常的'executeUpdate'。 – 2014-11-23 09:06:51

+0

@LuiggiMendoza SQL Server JDBC驅動程序不支持在批處理中執行插入操作(參考:[here](http://stackoverflow.com/q/13641832/2144390))。我剛剛測試了sqljdbc41.jar(版本4.1預覽版,最新版本,AFAIK),顯然仍然如此。 :( – 2014-11-23 12:15:45

回答

5

正如在前面的問題here,.getGeneratedKeys中提到的那樣,僅僅在.executeBatch之後才適用於SQL Server。我只是確認這是仍在使用的

  • SQL Server JDBC驅動程序(4.1預覽版),並
  • JTDS(1.3.1)

所以,看來最新版本的情況下您只需單獨執行插入操作,而無需批次。也就是說,不是這樣的

String[] stringsToInsert = new String[] { "foo", "bar", "baz" }; 
try (PreparedStatement ps = conn.prepareStatement(
     "INSERT INTO junk (textcol) VALUES (?)", 
     PreparedStatement.RETURN_GENERATED_KEYS)) { 
    for (String s : stringsToInsert) { 
     ps.setString(1, s); 
     ps.addBatch(); 
    } 
    ps.executeBatch(); 
    try (ResultSet rs = ps.getGeneratedKeys()) { 
     while (rs.next()) { 
      System.out.println(rs.getInt(1)); 
     } 
    } 
} 

代碼,你需要使用這樣的代碼

String[] stringsToInsert = new String[] { "foo", "bar", "baz" }; 
try (PreparedStatement ps = conn.prepareStatement(
     "INSERT INTO junk (textcol) VALUES (?)", 
     PreparedStatement.RETURN_GENERATED_KEYS)) { 
    for (String s : stringsToInsert) { 
     ps.setString(1, s); 
     if (ps.executeUpdate() > 0) { 
      try (ResultSet rs = ps.getGeneratedKeys()) { 
       rs.next(); 
       System.out.println(rs.getInt(1)); 
      } 
     } 
    } 
} 

請注意,您仍然可以使用.setAutoCommit(false)並在交易執行插入,只是不在批次

至於爲什麼該操作不被支持,一個JTDS功能要求here被申請了九(9)年前與其中一個答覆是

我得看看怎麼樣這個特性可以在jTDS中實現,然後再決定是否值得付出努力。

因爲無論JTDS也不是SQL Server的JDBC驅動程序已經實現了它(至少目前還沒有,它是on the radar爲Microsoft JDBC驅動程序),也許只是不適合該功能的需求就夠了。

附錄

作爲一種變通方法,我想這可能工作

String[] stringsToInsert = new String[] { "foo", "bar", "baz" }; 
try (Statement s = conn.createStatement()) { 
    s.executeUpdate(
      "CREATE TABLE #StuffToInsert (" + 
       "id INT IDENTITY(1,1) PRIMARY KEY, " + 
       "textcol NVARCHAR(100)" + 
      ")"); 
} 
try (PreparedStatement ps = conn.prepareStatement(
     "INSERT INTO #StuffToInsert (textcol) VALUES (?)")) { 
    for (String s : stringsToInsert) { 
     ps.setString(1, s); 
     ps.addBatch(); 
    } 
    ps.executeBatch(); 
} 
try (PreparedStatement ps = conn.prepareStatement(
     "INSERT INTO junk (textcol) SELECT textcol FROM #StuffToInsert", 
     Statement.RETURN_GENERATED_KEYS)) { 
    ps.executeUpdate(); 
    try (ResultSet rs = ps.getGeneratedKeys()) { 
     while (rs.next()) { 
      System.out.println(rs.getInt(1)); 
     } 
    } 
} 

可惜.getGeneratedKeys只返回該被插入的最後一行單生成的密鑰。

如果發送大量的個體(非批處理)插入通過網絡連接將是一個問題,那麼這個解決方法可能有所幫助:

String[] stringsToInsert = new String[] { "foo", "bar", "baz" }; 
try (Statement s = conn.createStatement()) { 
    s.executeUpdate(
      "CREATE TABLE #StuffToInsert (" + 
       "id INT IDENTITY(1,1) PRIMARY KEY, " + 
       "textcol NVARCHAR(100)" + 
      ")"); 
} 
try (PreparedStatement ps = conn.prepareStatement(
     "INSERT INTO #StuffToInsert (textcol) VALUES (?)")) { 
    for (String s : stringsToInsert) { 
     ps.setString(1, s); 
     ps.addBatch(); 
    } 
    ps.executeBatch(); 
} 
try (PreparedStatement ps = conn.prepareStatement(
     "SET NOCOUNT ON; " + 
     "DECLARE @GeneratedKeys TABLE(id INT IDENTITY(1,1) PRIMARY KEY, newkey INT); " + 
     "DECLARE @text NVARCHAR(100); " + 
     "DECLARE crsr CURSOR FOR " + 
     " SELECT textcol FROM #StuffToInsert ORDER BY id; " + 
     "OPEN crsr; " + 
     "FETCH NEXT FROM crsr INTO @text; " + 
     "WHILE @@FETCH_STATUS = 0 " + 
     "BEGIN " + 
     " INSERT INTO junk (textcol) VALUES (@text); " + 
     " INSERT INTO @GeneratedKeys (newkey) SELECT @@IDENTITY; " + 
     " FETCH NEXT FROM crsr INTO @text; " + 
     "END " + 
     "CLOSE crsr; " + 
     "DEALLOCATE crsr; " + 
     "SELECT newkey FROM @GeneratedKeys ORDER BY id; ")) { 
    try (ResultSet rs = ps.executeQuery()) { 
     while (rs.next()) { 
      System.out.println(rs.getInt(1)); 
     } 
    } 
} 

但這種做法不尊重自動提交在Java代碼中設置,所以回滾是不可能的。

0

這可能不是我常見的情況,我想.....這就是爲什麼jdbc驅動程序不支持這一點。

相關問題