1

我有一个 WCF 服务,它使用ODP.NET从 Oracle 数据库中读取数据。该服务也写入数据库,但间接地,因为所有更新和插入都是通过我通过 COM+ 访问的旧业务逻辑层实现的,我将其包装在TransactionScope中。旧层通过 ODBC 而不是 ODP.NET 连接到 Oracle。

我遇到的问题是,因为 Oracle 使用两阶段提交,并且由于较旧的业务层使用的是 ODBC 而不是 ODP.NET,所以事务有时会TransactionScope.Commit()在数据实际可用于从服务层读取之前返回。

我在 Stack Overflow 上看到了一个类似的帖子,关于一个 Java 用户遇到这样的问题。

Oracle 的一位代表发帖称,我对这个问题无能为力:

这可能是由于 OLETx ITransaction::Commit() 方法的行为方式。在 2PC 的第 1 阶段(即准备阶段)之后,如果一切成功, 即使资源管理器实际上还没有提交,提交也可以返回. 毕竟,成功的“准备”是保证资源管理器在此之后不能任意中止。因此,即使资源管理器因为没有收到来自 MSDTC 的“提交”通知(由于通信失败)而无法提交,组件的提交请求也会成功返回。如果您立即从表中选择行,您有时可能会在执行选择后看到实际提交发生在数据库中。因此,由于一致的读取语义,您的选择将不会看到新行。在 Oracle 中我们对此无能为力,因为“在第 1 阶段成功后提交成功”优化是 MSDTC 实施的一部分。

所以,我的问题是:

我应该如何处理可能的延迟(通过标题“asyc”)的问题,以确定 2PC 的第二部分何时实际发生,所以我可以确定我插入(间接)的数据实际上可以被选择Commit()通话返回后?

大型系统如何处理数据可能无法立即读取的事实?

4

1 回答 1

1

我假设整个事务已经准备好并且由 TransactionManager 决定提交结果,因此最终(除非启发式损坏)资源管理器将收到他们的提交消息并完成。但是,无法保证这可能需要多长时间 - 可能是几天,没有超时,在准备资源管理器中投票“提交”后,资源管理器必须等待听到集体结果。

在这些条件下,最简单的方法是采取“理解的,我们正在思考”的方法。你的请求被理解了,但你实际上不知道结果,这就是你告诉用户的。是的,在所有正常情况下,请求都会完成,但在某些情况下,操作员实际上可以选择手动干预事务(这样做可能会造成启发式损害。)

更进一步,您可以启动一个新事务并执行一些查询以查看数据是否存在。现在,如果您正在填充结果屏幕,您自然会执行诸如查询之类的操作。问题是如果没有预期的结果该怎么办。因此,再次告诉用户“您最近的请求正在处理中,点击刷新以查看它是否完成”。或者自动重试(我不太喜欢自动重试 - 更喜欢教育用户它实际上是一个异步操作。)

于 2009-11-20T20:16:06.557 回答