我有一个奇怪的问题,涉及使用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驱动程序。
请帮忙。
答案 0 :(得分:2)
我不知道JDBC驱动程序,但看起来很可疑你使用的是9.1版并连接到过时的PostgreSQL 8.3.19。将PostgreSQL升级到9.1可能会解决您的问题。
通常,如果您已将列time.time_id
和result_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();
所以这是我的坏事。这些症状很好地描述了缺少语句的代码行为。
我很感谢您的评论。有些人给了我新的研究领域。谢谢欧文。