2017-12-27 224 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 (?, ?, ?)"; 

如果你不知道的运行之前的参数个数,你必须建立在运行时查询。上面的链接中给出了一个例子。