2017-12-27 329 views
1

我正在使用舊的struts應用程序,並且我需要通過java批處理(因爲我們可能一次添加數千行)將數據保存到數據庫中。preparedStatement.addBatch()添加空參數

因此,我用這樣的代碼:

Connection c = null; 
PreparedStatement batch = null, truncate=null; 
String sql = "INSERT INTO ? VALUES (?)"; 
try { 
    c = getConnection(); 
    c.setAutoCommit(false); 
    batch = c.prepareStatement(sql); 
    for (ClassContainingData bean : values) { 
     batch.setString(1, bean.getTableName()); 
     batch.setString(2, bean.getAllFieldsValues()); 
     batch.addBatch(); 
    } 
    int[] resultats = batch.executeBatch(); 
    for(int res : resultats) { 
     if(res == PreparedStatement.EXECUTE_FAILED) { 
      batch.close(); 
      c.close(); 
      throw new SQLException("L'ajout des valeurs en base de données a échoué pour au moins une valeur."); 
     } 
    } 
    c.commit(); 
} 
catch (BatchUpdateException b) { 
    throw new ServiceException("Erreur lors de l'exécution du batch", b); 
} 
catch (SQLException s) { 
    throw new ServiceException("Impossible de sauvegarder les beans en base.", s); 
} 
finally { 
    getManager().close(batch); 
    freeConnection(c); 
} 

的錯誤消息是法語,因爲我在一家法國公司,我們對此深感抱歉工作。

所以這段代碼是非常基本的,因爲它受到了我在這裏和網上找到的所有例子的啓發,但是我有一些模糊的錯誤,我沒有找到任何信息。

當我運行的是,我得到一個異常

CAUSE : java.sql.BatchUpdateException: ORA-00903: invalid table name. 

這指出了我的數據錯誤,所以我雙重檢查,但我似乎輸入沒事。

弄明白,我用Eclipse調試器來查看我的preparedStatement運行時的值,並且我發現addBatch()增加了一個空集的參數給我preparedStatement

以下是運行時值的截圖:左圖是運行addBatch()語句之前,右圖是在此語句之後。

Screenshot of runtime values

正如你所看到的,包含我的字符串參數數組現在持有的第二行,其中只包含null值。

注意數據:

  • 這是第一次迭代的for循環,所以它應該持有一個行
  • 的SQL語句有兩個參數:一個表名,像TABLE_NAME,和要插入的值的格式化列表,如'Here', 'are', 'values'

無論我使用1行輸入還是15行輸入(是的,我談論了數千行,但目前處於測試階段),我都有同樣的問題,如果這可能是相關的。

有什麼想法在這裏出了什麼問題?我不認爲我濫用了addBatch()聲明,我寧願認爲我傳遞了不適當的數據。

編輯:

我撤回表名從參數和SQL命令是現在像 「INSERT INTO」 +表名+ 「VALUES(?)」

這導致了一個不同的錯誤,但它不能解決問題!

確實,table_name現在是正確的,但[null]行仍然被添加到批處理中。因此,在批次,其中拋出 空值「java.sql.BatchUpdateException:ORA-00947:沒有足夠的價值觀」

我的問題是不是由AlexH標註問題的重複,請撤銷該商標。

+0

或者[如何使用java編寫語句插入的表名變量](https://stackoverflow.com/questions/11312155/how-to-use-a-tablename-variable-for-a-java-prepared -statement-insert)以匹配您的查詢 – AxelH

+0

原因是在設置任何值之前,準備好的語句將被解析並優化。這就是爲什麼_PS_更快。該查詢被解析一次,並且稍後提出這些值,以便DBMS不知道如何處理先前收到的優化查詢。對於解決方案,它取決於'bean.tableName'的來源,看看可以做什麼。 – AxelH

+0

你給的第一個鏈接有一些有趣的信息:table-name不能被參數化在preparedStatement中!我會嘗試這個修復,我會告訴你。 – Heratom

回答

1

此問題與我在同一程序中遇到的另一個問題有關。 討論和解決方案是here

作爲一個總結,應該知道一個preparedStatement不能使用表名作爲參數,也不能將多個值放在參數中。

例如在我的情況,我試圖做這樣的事情:

String sql = "INSERT INTO (?) VALUES (?)" 
preparedStatement ps = connection.prepareStatement(sql); 
ps.setString(1, "myTableName"); 
ps.setString(2, "'Value1', 'Value2', 3"); 

正如你看到的,我想3個參數作爲一個傳遞,沒有differenciating字符串和整數(和日期)。

一個PreparedStatement可以處理的唯一格式如下:

String sql = "INSERT INTO " + tableName + " VALUES (?, ?, ?)"; 

如果你不知道的運行之前的參數個數,你必須建立在運行時查詢。上面的鏈接中給出了一個例子。