Java Oracle在提交和选择之间存在延迟

Java Oracle在提交和选择之间存在延迟,java,sql,database,oracle,websphere,Java,Sql,Database,Oracle,Websphere,我们有一个Java工作流应用程序,它使用Oracle数据库跟踪其步骤以及与其他服务的交互。在工作流运行期间,会执行多个插入/更新/选择,有时选择不会返回更新的数据,即使插入/更新提交在成功完成之前已运行。工作流出错后(由于数据不正确),如果我们返回并通过第三方应用程序检查数据库,则会显示新的/更新的数据。在我们的承诺完成和可见之间似乎有一个延迟。这种情况大约发生在所有工作流运行的2%中,并且在大量使用数据库时会增加 我们的数据库支持团队建议将参数max commit propagation de

我们有一个Java工作流应用程序,它使用Oracle数据库跟踪其步骤以及与其他服务的交互。在工作流运行期间,会执行多个插入/更新/选择,有时选择不会返回更新的数据,即使插入/更新提交在成功完成之前已运行。工作流出错后(由于数据不正确),如果我们返回并通过第三方应用程序检查数据库,则会显示新的/更新的数据。在我们的承诺完成和可见之间似乎有一个延迟。这种情况大约发生在所有工作流运行的2%中,并且在大量使用数据库时会增加

我们的数据库支持团队建议将参数max commit propagation delay更改为0,因为它默认为700。这似乎是一个可能的解决方案,但最终并没有解决我们的问题

应用程序在WebSphere上运行,Oracle数据库配置为JDBC数据源。我们正在使用Oracle 10.1g。应用程序是用Java1.5编写的

任何帮助都将不胜感激

编辑:示例代码

DataSource ds; // spring configured

String sql = "INSERT INTO " + currentTable + " (" + stepId + ',' + stepEntryId + ", " + stepStepId + ", " + stepActionId + ", " + stepOwner + ", " + stepStartDate + ", " + stepDueDate + ", " + stepFinishDate + ", " + stepStatus + ", " + stepCaller + " ) VALUES (?, ?, ?, null, ?, ?, ?, null, ?, null)";

Connection conn = ds.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql);
// set values
stmt.executeUpdate();
// close connections

// later on in the code...
Connection conn = ds.getConnection();
PreparedStatement stmt = null;
ResultSet rset = null;

String sql = "SELECT " + stepId + ", " + stepStepId + ", " + stepActionId + ", " + stepOwner + ", " + stepStartDate + ", " + stepDueDate + ", " + stepFinishDate + ", " + stepStatus + ", " + stepCaller + " FROM " + currentTable + " WHERE " + stepEntryId + " = ?";
stmt = conn.prepareStatement(sql);

stmt.setLong(1, entryId);

rset = stmt.executeQuery();
//close connections

你在使用ORM吗?它可能是从缓存中选择,而不是在更改后形成数据库。

默认情况下,您描述的行为应该是不可能的-在提交的事务中所做的更改将立即对所有会话可用。但是,也有例外情况:

  • 您是否在COMMIT命令中使用任何写入选项?如果没有,请确认COMMIT_WRITE初始化参数的值。如果使用“WRITE BATCH”或特别是“WRITE BATCH NOWAIT”,您可能会遇到并发问题。“WRITE BATCH NOWAIT”通常用于写事务的速度比可能的并发问题更重要的情况。如果初始化参数使用“WRITE”变量,则可以通过在提交()中指定IMMEDIATE子句在事务基础上重写它

  • 试图读取数据的事务是否在提交另一个事务之前调用SET事务?使用SET TRANSACTION指定序列化级别为只读或可序列化将导致事务在调用SET TRANSACTION()后未看到其他已提交会话发生的更改

  • 编辑:我看到您正在使用一个数据源类。我不熟悉这个类-我假设它是一个连接共享资源。我意识到,您当前的应用程序设计可能不便于在整个工作流程中使用相同的连接对象(这些步骤可能设计为独立操作,并且您没有在设备中构建一个连接对象从一个步骤传递到下一个步骤),但是,您应该验证返回到数据源对象的连接对象是否“干净”,特别是对于打开的事务。您可能没有在代码中调用SET事务,但其他地方的数据源的另一个使用者可能正在这样做,并在会话仍处于可序列化或只读模式时将连接返回到数据源。当连接共享时,必须先回滚所有连接,然后再将其交给新的使用者


    如果您无法控制或查看数据源类的行为,您可能希望尝试对新获取的连接执行回滚,以确保它没有已建立的延迟事务。

    如果DBA团队试图修改
    max\u commit\u propagation\u delay
    参数,这可能意味着您正在连接到一个RAC实例(即:多个不同的服务器访问一个数据库)

    在这种情况下,当您在java代码中关闭并重新打开连接时,可能会有其他服务器响应您的请求。延迟参数意味着当两个实例不在完全相同的时间点时,存在一个小的时间范围。您得到的答案与某个时间点一致,但可能不是最新的

    正如KM所建议的,最简单的解决方案是在提交后保持连接打开


    或者,如果可行的话,您也可以在关闭连接后添加延迟(例如,如果这是一个批处理作业,响应时间并不关键)。

    这听起来像是RAC的问题,连接到两个不同的实例,并且SCN不同步

    作为解决方案,考虑不要关闭数据库连接并获得新的连接,但重用相同的连接。

    如果这不可行,则向查询中添加一次重试,尝试检索插入的行。如果未返回该行,请稍睡片刻,然后重试查询。将其放入一个循环,在指定的重试次数后,您可能会失败

    [增编]

    史蒂夫·布罗伯格(Steve Broberg(+1!)在他的回答中提出了一些有趣的想法。我没有考虑:

    • COMMIT
      可能不是立即等待
    • 事务隔离级别可以是除读提交之外的任何级别

    我确实考虑过闪回查询的可能性,并且没有提到它就把它驳回了,因为OP没有明显的理由使用闪回查询,也没有证据表明代码片段中有这样的事情。


    [/address]

    一种可能的解决方法可能是使用JTA事务。 它通过多个打开/关闭的jdbc连接保持“幕后”连接打开。也许它会让你的连接保持在同一台服务器上,避免这个同步问题

    UserTransaction transaction = (UserTransaction)new InitialContext().lookup("java:comp/UserTransaction");
    transaction.begin();
    // doing multiple open/close cxs
    transaction.commit();
    

    代码片段实际上没有包含提交

    如果您假设/依赖于执行提交的关闭连接,那么它可能不是同步的(即java可能会在通知Oracle关闭连接时报告连接已关闭,这意味着可能是在提交完成之前)