ExecuteBatch和Prepared Statements的奇怪行为

时间:2012-06-23 06:39:13

标签: java postgresql jdbc

我有一个奇怪的问题,涉及使用JDBC将大量数据放入PostgSQL数据库的executeBatch和Prepared Statements。我每次都使用executeBatch向数据库发送50,000个语句。

我知道执行批处理和准备好的语句正在运行;一些数据正在进入数据库。 准备好的陈述是

  INSERT INTO time ( time_id, log_id, phenomenon_time, qc_phenomenon_time )
  SELECT nextval( 'time_seq' ), ?, ?, ?

并使用执行批处理,数据可在数据库中找到。

使用以下准备好的陈述时,

  INSERT INTO result_3d ( result_3d_id, time_id, variable_id, value, qc_value ) 
  SELECT nextval( 'result_3d_seq' ), ( SELECT t.time_id 
                                       FROM time t 
                                       WHERE t.log_id = ? 
                                       AND t.phenomenon_time = ? ), ?, ?, ?

使用执行批处理,数据库中没有数据。我甚至打开了数据库日志记录,发现了第一个的所有内容,但第二个没有找到。第二个准备好的语句依赖于第一个的数据,但数据库甚至没有看到第二个。

没有抛出异常。唯一奇怪的是,对于第二个预处理语句,返回的数组的大小为零。执行批处理立即返回。是否允许在第二个准备好的声明中使用子查询?

我使用postgres-9.1-901.jdbc4.jar作为针对PostgreSQL v8.3.19数据库的JDBC驱动程序。

请帮忙。

2 个答案:

答案 0 :(得分:2)

我不知道JDBC驱动程序,但看起来很可疑你使用的是9.1版并连接到过时的PostgreSQL 8.3.19。将PostgreSQL升级到9.1可能会解决您的问题。

通常,如果您已将列time.time_idresult_3d.result_3d_id定义为serial列(您可能应该这样做),或者您已将这些列的DEFAULT值设置为{{ 1}}手动在相应的序列上,无需从序列中获取ID。这些值将自动填充

  

第二个准备好的声明中的子查询是否允许?

是的,它是 - 原则上。但它可能永远不会返回多行。您必须保证nextval()的唯一性或添加(t.log_id, t.phenomenon_time)

LIMIT 1

使用PostgreSQL 9.1,您可以将两个(SELECT t.time_id FROM time t WHERE t.log_id = ? AND t.phenomenon_time = ? LIMIT 1) 命令与data-modifying CTE链接在一起,这应该要快得多,并且不需要以子查询开头:

INSERT

所有这些可能会或可能不会解决潜在的问题,但它很有可能。

我的第一个想法是底层问题可能是并发问题 - 意味着第二个WITH data (log_id, phenomenon_time, qc_phenomenon_time ,variable_id, value, qc_value ) AS ( VALUES(?, ?, ?, ?, ?, ?) -- cast to appropriate types! ) , i AS ( INSERT INTO time (log_id, phenomenon_time, qc_phenomenon_time) SELECT log_id, phenomenon_time, qc_phenomenon_time FROM data RETURNING time_id, log_id, phenomenon_time ) INSERT INTO result_3d (time_id, variable_id, value, qc_value) SELECT i.time_id, d.variable_id, d.value, d.qc_value FROM data d JOIN i USING (log_id, phenomenon_time); 在第一个提交之前启动。但是如果数据库甚至没有看到第二个调用,那么必须有其他工作。

答案 1 :(得分:2)

我将回答我自己的问题,因为我所描述的症状与执行批处理或准备语句无关。在一些重构过程中,我遗漏了一个重要的声明。

this.preparedStatement.addBatch();

所以这是我的坏事。这些症状很好地描述了缺少语句的代码行为。

我很感谢您的评论。有些人给了我新的研究领域。谢谢欧文。