无法在Postgres / JDBC中隔离跨层的事务

时间:2012-05-01 20:58:31

标签: java sql postgresql jdbc

我正在开发一个Java项目,该项目包含 PostgresSQL 9.0 数据库层,使用 JDBC 。 SQL包含在函数中,在 Java 中执行,就像使用JDBC的存储过程一样。

数据库需要 header-detail 方案,详细记录需要标题的外键ID。因此,首先写入标题行,然后写入几千个详细记录。 我需要阻止用户访问标题,直到详细信息写完为止。

您可以建议包装整个事务,以便在详细记录完成写入之前无法提交标头记录。但是,您可以在下面看到我已将事务隔离到Java中的调用:写入标头,然后循环访问详细信息(同时编写详细信息行)。由于数据的庞大规模,将详细数据传递给函数执行一次交易是不可行的。

我的问题是:如何在JDBC级别包装事务,以便在详细记录完成写入之前不提交标题?

最佳解决方案隐喻是SQL Server的命名事务,其中事务可以在数据访问层代码中启动(在其他事务之外),并在稍后的数据库调用中完成。

以下(简化)代码执行时没有错误,但不解决隔离问题:

DatabaseManager mgr = DatabaseManager.getInstance();
Connection conn = mgr.getConnection();
CallableStatement proc = null;

conn.setAutoCommit(false);
proc = conn.prepareCall("BEGIN TRANSACTION");
proc.execute();

//Write header details
writeHeader(....);
for(Fault fault : faultList) {
    writeFault(fault, buno, rsmTime, dnld, faultType, verbose);
}
proc = conn.prepareCall("COMMIT TRANSACTION");
proc.execute();

非常感谢您的精彩回答!

2 个答案:

答案 0 :(得分:3)

您是否对writeHeader和writeFault使用相同的连接?

conn.setAutoCommit(false);

headerProc = conn.prepareCall("headerProc...");
headerProc.setString(...);
headerProc.execute();

detailProc = conn.prepareCall("detailProc...");

for(Fault fault : faultList) {
    detailProc.setString(...);
    detailProc.execute();
    detailProc.clearParameters();
}

conn.commit();

然后你应该真正看一下这个细节循环的“addBatch”。

答案 1 :(得分:2)

虽然您似乎已经解决了当前的问题,但如果您在Java EE容器内运行,则可能需要查看JTA。结合EJB3.1 *的JTA允许您进行声明式事务控制,并根据我的经验大大简化事务管理。

*不用担心,EJB3.1比以前的EJB规范更简单,更简洁,更少可怕。