如何模拟数据库失败以测试Java中的两阶段提交

时间:2012-04-11 15:01:17

标签: java database transactions websphere 2phase-commit

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

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

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

是否有可以帮助我这样做的模拟器/模拟器或工具?

4 个答案:

答案 0 :(得分:4)

那是很多问题:)我会尝试完成以前的答案。

Is there a better way to simulate the DB failure?

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

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

Communications between the three parts

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

请注意,很难控制参与者的参与顺序(参见this question)。因此很容易测试其中一个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?

ManagedConnection可以通知交易管理员。其中一个通知是ConnectionEvent.CONNECTION_ERROR_OCCURRED,通知它使用此特定连接时发生错误。

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

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

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?

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

答案 1 :(得分:1)

可能您可以添加自己的参与提交的资源,并在第一阶段之后暂停事务。在此期间,你可以“拔掉插头”。

答案 2 :(得分:1)

Andrej回答了问题的一部分,让我回答第二部分。

您在应用程序中获得的Connection对象只是物理连接的包装器。该包装器在连接池和事务管理中起作用。如果数据库出现任何问题,连接包装器将变得无法使用,您只能回滚。这是有道理的,因为您只在2PC启动之前访问连接,并且无法恢复在2PC启动之前完成的任何操作。

请注意,尝试释放连接并获取新连接并不会改变任何内容,因为一旦在事务中使用了来自给定数据源的连接,您将始终从该数据源获得相同的连接。只要你在同一笔交易中。这意味着您的应用程序无法重新连接"无需重新启动整个交易。

另一方面,如果在准备好所有资源之后但在所有资源都已提交之前出现问题,那么事务管理员有责任恢复该事务。但这发生在幕后,你的应用程序无法控制。此时,您的应用程序应该已经释放了该事务中使用的所有连接。

答案 3 :(得分:0)

您最好的选择可能是在内存数据库中使用。调用失败并检查前后数据源的状态,以确保正确执行回滚/提交。

至于你的其他问题,这些似乎是极高的成本/低回报测试。阅读供应商文档并确保正确配置您的事务环境。一个这样做你可能应该自动化它所以它的手。

除非您编写了自己的2PC协议特定的事务管理器+数据库实现,否则我会将这些功能的测试留给您的供应商。