2009-06-11 87 views
8

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

我们的数据库支持团队建议的参数最大提交传播延迟更改为0,因为它默认为700这似乎是一个可行的解决方案,但最终还是没有解决我们的问题。

应用程序在WebSphere上运行,并且Oracle数据库被配置为JDBC数据源。我们正在使用Oracle 10.1g。该应用程序是用Java 1.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 
+0

从[Oracle文档](http://download.oracle.com/docs/cd/B14117_01/server.101/b10755/initparams115.htm),似乎参数`max_commit_propagation_delay`仅适用于RAC设置。您是否连接到RAC实例? – 2009-06-11 20:14:58

+0

数据是作为交易的一部分提交的吗?或读? – 2009-06-11 20:16:34

回答

1

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

+0

我们不使用ORM,这些表和sql语句是非常基本的,只是用来存储少量的跟踪信息。 – Andrew 2009-06-11 20:13:24

+0

发布代码片段如果可能... – 2009-06-11 20:18:04

+1

如果@Steve Broberg的建议不起作用,你可以尝试使用相同的连接 – 2009-06-11 21:03:51

6

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

  1. 您是否正在使用COMMIT命令中的任意WRITE选项?如果不是,请确认COMMIT_WRITE初始化参数的值。如果要么使用“WRITE BATCH”,要么使用“WRITE BATCH NOWAIT”,你可能会面临并发问题。 “WRITE BATCH NOWAIT”通常用于写入事务的速度比可能的并发问题更重要的情况。如果你的初始化参数是使用“写”的变体,您可以通过在你的提交(see COMMIT)指定IMMEDIATE子句覆盖它交易的基础上

  2. 是试图读取数据调用SET交易前的交易到其他交易提交?使用SET TRANSACTION指定SERIALIZATION级读ONLY或SERIALIZABLE会导致看不可更改自其他承诺会话的发生SET交易的调用后发生的交易(see SET TRANSACTION

编辑:我看到你'使用一个DataSource类。我对这个班不熟悉 - 我认为这是一个连接共享资源。我意识到你目前的应用程序设计可能并不便于在整个工作流程中使用相同的连接对象(这些步骤可能设计为独立运行,而且你没有建立一个工具来将连接对象从一个步骤传递到下一步),但您应该验证返回到DataSource对象的连接对象是否“干净”,特别是关于打开的事务。你可能没有在你的代码中调用SET TRANSACTION,但其他地方的DataSource的其他用户可能会这样做,并且会话仍然以SERIALIZABLE或READ ONLY模式返回到数据源。当连接共享时,所有连接都必须回滚,然后再交给新的消费者。

如果您对DataSource类的行为没有控制权或可见性,那么您可能希望尝试在新获取的连接上执行ROLLBACK,以确保它没有已建立的延迟事务。

4

如果DBA团队试图修改max_commit_propagation_delay参数,则可能意味着您正在连接到RAC实例(i-e:访问单个数据库的多个不同服务器)。

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

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

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

0

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

作为一种解决方法,请考虑不关闭数据库连接并获取新连接,但重新使用相同的连接。

如果这样做不可行,那么向试图检索插入的行的查询添加一个重试。如果行没有被返回,然后睡一会儿,然后再次重试查询。把它放到一个循环中,经过指定的重试次数后,你可以失败。

[附录]

在他的回答,史蒂夫布罗贝里(+1!)提出了有趣的想法。我没有考虑:

  • COMMIT可能比IMMEDIATE WAIT
  • 以外的任何事务隔离级别可能会比任何其他READ COMMITTED

我确实考虑过闪回查询的可能性,因为没有任何明显的原因OP会使用闪回查询,并且在代码片段中没有这种事物的证据),所以不予理睬就抛弃了。)

[/ ADDENDUM]

0

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

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

代码片段实际上并未包含提交。

如果您假设/依靠关闭连接进行提交,它可能不同步(即,当它告诉Oracle关闭连接时,java可能会报告连接已关闭,这意味着它可能在提交由Oracle完成)。

0

我看不到在您的代码提交。他们是这样一个应用程序中最重要的陈述,所以我希望每次都明确写出它们,而不是依赖于close()或其他。

默认情况下,您可能会将autocommit设置为true,以正确解释行为(每次插入/更新后提交)。

您可以检查,确认您确实在您想要的位置提交,例如在交易结束时,而不是之前?

如果当你部分通过时有提交,那么你的线程之间有一个竞争条件,这也解释了当负载较大时为什么还有更多的问题。

0

“尽管在成功完成之前运行的插入/更新提交。”

这向我建议你发出一个commit(),然后期望再次读取完全相同的数据(这是可重复读取的)。

这表明我不应该犯。只要你想确保没有其他任务能够修改你明确期望保持稳定的任何数据,你就不能释放锁(这就是commit所做的)。

请注意,尽管您对某些资源保持锁定,但其他线程将堆叠起来“等待该资源变为可用”。在释放锁定时,该堆栈非空的可能性会随着通用系统负载的增加而变得更高。当你(最终)发布“提交”时,你的数据库管理系统将会得出什么结论,是得出结论:“嘿,哇,这个人终于完成了这个资源,所以现在我可以去让所有其他等待的人尝试做他们的事情(并没有什么可以阻止“他们的事情”成为更新!)“。

也许有些问题与我忽略的Oracle快照隔离有关。如果是的话,道歉。