Java 通过ExecuteBack和准备好的语句进行奇怪的行为

Java 通过ExecuteBack和准备好的语句进行奇怪的行为,java,postgresql,jdbc,Java,Postgresql,Jdbc,我有一个奇怪的问题,涉及executeBatch和Prepared语句,它们使用JDBC将大量数据放入PostgSQL数据库。我使用executeBatch每次向数据库发送50000条语句 我知道执行批处理和准备的语句正在工作;一些数据正在进入数据库。 准备好的声明是 INSERT INTO time ( time_id, log_id, phenomenon_time, qc_phenomenon_time ) SELECT nextval( 'time_seq' ), ?, ?, ?

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

我知道执行批处理和准备的语句正在工作;一些数据正在进入数据库。 准备好的声明是

  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 = ? ), ?, ?, ?
使用“执行批处理”时,数据库中没有数据。我甚至打开了数据库日志记录,第一次发现了所有内容,第二次却什么都没有。第二条准备好的语句依赖于第一条语句的数据,但数据库甚至看不到第二条语句

没有抛出异常。唯一奇怪的是,对于第二个prepared语句,返回的数组大小为零。excute批立即返回。是否允许第二条准备语句中的子查询

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


请帮助。

我不知道JDBC驱动程序,但您使用9.1版并连接到过时的PostgreSQL 8.3.19似乎有点可疑。将PostgreSQL升级到9.1可能会解决您的问题

通常,如果您已将列
time.time\u id
result\u 3d.result\u id
定义为列(您可能应该这样做),或者如果您已手动将这些列的默认值设置为相应序列上的
nextval()
,则无需从序列中获取id。这些值将自动填写

是否允许第二条准备语句中的子查询

是的,原则上是这样。但它可能永远不会返回超过一行。您必须保证
(t.log\u id,t.performance\u time)
或添加
限制1

(SELECT t.time_id 
 FROM time t 
 WHERE t.log_id = ? 
 AND t.phenomenon_time = ?
 LIMIT 1)
使用PostgreSQL 9.1,您可以将两个
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);
所有这些都可能会或可能不会解决根本问题,但很有可能会解决


我的第一个想法是,潜在的问题可能是并发性问题——这意味着在提交第一个
INSERT
之前启动第二个
INSERT。但是,如果数据库甚至看不到第二个调用,那么这里肯定还有其他东西在起作用。

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

this.preparedStatement.addBatch();
这是我的错。这些症状完美地描述了带有缺失语句的代码的行为

this.preparedStatement.addBatch();

我感谢你在评论中所作的努力。有些人给了我新的学习领域。谢谢Erwin。

我正在尝试进行重新定义测试,因此会有一个具有较早数据库的较新驱动程序。第二行中的子查询很可能只返回一行,但由于db甚至没有看到它,db无法检查约束。虽然CTE的数据模型很有趣,但不适合这里。第一条语句执行,比如说,用1M的时间填充时间表。第二条语句对数量不允许的变量执行1M次。由于数据类型不匹配,第2条语句确实发生了一些问题。但它现在根本没有执行,可以在较早的服务器版本中使用较新的JDBC驱动程序版本;只是不要反过来做。在子查询中添加
限制
是一种非常不安全的解决方法,没有
ORDER BY
;这将导致不可预测和不可重复的行为。抄送@BrettWalker@CraigRinger:添加
限制1
只是为了修复错误。如果子查询可以返回多行,则需要重新考虑整个设置。建议的CTE将消除潜在的故障点。
在postgresql.conf中设置log_语句='all'
,并重新启动/重新加载Pg(如果尚未启动)。将
loglevel=2
添加到创建连接时传递的PgJDBC参数中。然后检查PgJDBC日志(通过您现有的java日志记录)和Pg日志(在datadir中的
Pg_log
,或在
/var/log/
)中)。更多信息也会有所帮助:在针对该数据库测试旧PgJDBC时也会发生这种情况吗?在测试一个新的PgJDBC和一个当前的Pg时怎么样?您需要测试这些配置以隔离故障。