如何在 Java 中模拟数据库故障以测试两阶段提交

我正在实施一个涉及分布式资源的两阶段提交。如何模拟参与数据库的故障?拔出网线不起作用,因为它会导致表死锁。我目前正在我的应用程序代码中使用钩子,这些钩子在不同的点上抛出,比如在查询执行之前,在查询执行之后。我对这种方法的关注点是:StaleConnectionException

  • 有没有更好的方法来模拟数据库故障?
  • 当数据库连接损坏时,连接对象会发生什么情况?它是保留其值还是变为 null?
  • 当应用程序尝试重新连接到数据库时,实际会发生什么情况?连接对象获取什么值?它是否使用连接池中的现有值?

我还想在中间点进行测试,例如在查询执行期间,在提交期间(发送准备后等)。现在,我将应用程序置于调试模式,并单步执行函数调用并在两者之间拔下插头。但这种方法是手动的,不适用于规模测试。

有没有模拟器/模拟器或工具可以帮助我做到这一点?


答案 1

这是很多问题:)我将尝试完成前面的答案。

Is there a better way to simulate the DB failure?

测试所有案例都很复杂。测试主要情况的一种方法是创建一个JCA连接器(数据库驱动程序一个JCA连接器)。您可以从将在事务中登记的连接器(第三个参与者)获取连接。然后,连接可能会引发某些错误。

有三个部分协同工作:(1) 应用程序,(2) 应用程序服务器的事务管理器,以及 (3) jca 连接器(所谓的资源适配器)。

Communications between the three parts

连接通过 将自身挂接到事务中。使用自定义 JCA 连接器,您可以向应用程序(在 picutre 中)或应用程序服务器的事务管理器(通过图片中获取)引发异常。您可以在 和 期间引发异常,这与 2 阶段提交期间的错误相对应。ManagedConnection.getXAResourceConnectionXAResourceManagedConnectionXAResource.prepareXAResource.commit

请注意,很难控制参与者的兴奋顺序(见此问题)。因此,很容易测试其中一个失败(即您的失败),但很难控制它们的调用顺序。重现 2 阶段提交的所有可能的无效状态很复杂,尤其是在进行优化时。prepare

(我曾经写过一个JCA连接器(http://code.google.com/p/txfs),如果你想要示例代码,周围还有其他连接器。

What happens to the connection object when DB connection goes bad? 
Does it retain its value or does it become null?

可以通知事务管理器。其中一个通知是通知它使用此特定连接时发生错误。ManagedConnectionConnectionEvent.CONNECTION_ERROR_OCCURRED

如其他答案中所述,通常每个事务都有一个关联的托管连接。托管连接将物理连接抽象化,并且您不希望使用太多物理连接。该应用程序仅获取“句柄”(如图所示)。在一个给定事务中获取的句柄都指向同一个托管连接。这是大多数应用服务器支持的优化。Connection

如果托管连接变得无效,则使用它的句柄也会变为无效。但是手柄可以不被“刷新”。事务必须回滚,托管连接将被销毁。当另一个事务启动时,它将与池中的另一个有效托管连接相关联。

What actually happens when application tries to reconnect to DB?
What value does connection object get?
Does it use an existing value from the connection pool?

应用服务器管理托管连接池。如前一段所述,在使用时可能会变坏。但是,如果不加以使用,一个人也可能变坏。例如,池中已使用的托管连接可能会因基础物理连接超时而变得无效。应用服务器通常具有一项功能,用于在开始使用托管连接之前测试该连接是否有效。如果没有,它将尝试池中的另一个托管连接,或创建一个新连接。


答案 2

也许您可以添加自己的资源,这些资源将参与提交,并在第一阶段之后暂停事务。与此同时,您可以“拔掉插头”。


推荐