Java 使用Spring和Hibernate跨多个数据库执行分布式事务的“最佳”方法是什么

Java 使用Spring和Hibernate跨多个数据库执行分布式事务的“最佳”方法是什么,java,hibernate,spring,transactions,xa,Java,Hibernate,Spring,Transactions,Xa,我有一个应用程序——更像是一个实用程序——它位于一个角落,定期更新两个不同的数据库 它是一个小型独立应用程序,使用Spring应用程序上下文构建。上下文中配置了两个Hibernate会话工厂,依次使用Spring中配置的Commons DBCP数据源 目前没有事务管理,但我想补充一些。对一个数据库的更新取决于对另一个数据库的成功更新 该应用程序并不位于JavaEE容器中——它是由一个从shell脚本调用的静态启动器类引导的。launcher类实例化应用程序上下文,然后调用其中一个bean上的方法

我有一个应用程序——更像是一个实用程序——它位于一个角落,定期更新两个不同的数据库

它是一个小型独立应用程序,使用Spring应用程序上下文构建。上下文中配置了两个Hibernate会话工厂,依次使用Spring中配置的Commons DBCP数据源

目前没有事务管理,但我想补充一些。对一个数据库的更新取决于对另一个数据库的成功更新

该应用程序并不位于JavaEE容器中——它是由一个从shell脚本调用的静态启动器类引导的。launcher类实例化应用程序上下文,然后调用其中一个bean上的方法

在数据库更新中使用事务性的“最佳”方法是什么


我将把“最佳”的定义留给您,但我认为它应该是一些“易于设置”、“易于配置”、“便宜”和“易于打包和重新分发”的功能。当然,自由和开放源码软件会很好。

在您的上下文中设置事务管理器。Spring文档有一些示例,非常简单。然后,当您要执行事务时:

try { 
    TransactionTemplate tt = new TransactionTemplate(txManager);

    tt.execute(new TransactionCallbackWithoutResult(){
    protected void doInTransactionWithoutResult(
            TransactionStatus status) {
        updateDb1();
        updateDb2();
    }
} catch (TransactionException ex) {
    // handle 
}
有关更多示例和信息,请参见以下内容:

当你说两个不同的数据库时,你是指不同的数据库服务器,还是指同一个DB服务器中的两个不同模式

如果是前者,那么如果您想要完全事务性,那么您需要XA事务API,它提供完整的两阶段提交。但更重要的是,您还需要一个事务协调器/监视器来管理不同数据库系统之间的事务传播。这是JavaEE规范的一部分,并且是其中非常精巧的一部分。TX协调器本身是一个复杂的软件。如果您希望与协调员交谈,请通过Spring访问您的应用程序软件


但是,如果您只是指同一DB服务器中的两个数据库,那么普通JDBC事务应该可以正常工作,只需在一个事务中对两个数据库执行操作。

在这种情况下,您需要一个支持XA协议的事务监视服务器,并确保您的数据库也支持XA。最重要的是?J2EE服务器内置了事务监视器。如果您的代码没有在J2EE服务器上运行,那么有很多独立的替代方案—Atomicos、Bitronix等。

在多个数据库上分发事务的最佳方法是:不要

有些人会把你指向XA,但XA或两阶段提交是一个谎言或谎言

想象一下:在第一阶段告诉XA管理器它可以发送最终提交后,到其中一个数据库的网络连接失败。现在怎么办?暂停?这将导致另一个数据库损坏。回降?两个问题:无法回滚提交,如何知道第二个数据库发生了什么?可能网络连接在成功提交数据后失败,只有成功消息丢失

最好的方法是在单个位置复制数据。使用允许您随时中止复制并继续复制的方案,例如,忽略您已经拥有的数据,或订购副本的“按ID选择”和“仅请求记录”>“最大ID”。用事务来保护它。这不是问题,因为您只从源数据库读取数据,所以当事务因任何原因失败时,您可以忽略源数据库。因此,这是一个普通的旧单源事务


复制数据后,在本地处理。

您可以尝试Spring ChainedTransactionManager,它支持分布式数据库事务。这可能是XA的更好替代方案

分布式事务必须统计所有4个ACID属性。你怎么回事啊?您描述的场景不可能发生,因为管理器正在相互通信,并且只有在所有参与节点都交换了GO时才进行提交。@Falcon:那么,如果网络在准备和提交之间失败,会发生什么情况呢?或者其中一个服务器死了?不可能发生事实上不可能发生。不,不会指示它们回滚,因为在此场景中,某些节点已经提交。当崩溃的节点可用时,事务协调器会告诉它再次提交。因为节点在准备阶段做出了积极的响应,所以它需要能够提交,即使它从崩溃中恢复过来。我发现支持该标准的人太多了,不能被一个人的轶事证据所左右。谢谢你的评论。@Nicholas我发现只有那些通过解决这个标准带来的问题来赚钱的公司才会广泛支持我。消费者=不得不忍受这种解决方案的人通常会尝试一次,然后寻找更好的解决方案。尽管如此,我的答案在逻辑上是合理的。我的方法比其他方法简单得多
nxa和我可以证明它总是有效的。XA更像是一个承诺,而不是事实。这个例子并没有真正回答这个问题,甚至回答错误:OP提到他配置了两个Hibernate会话工厂,这需要两个独立的事务管理器。答案中的示例仅使用一个未指定的事务管理器。因此,使用单个Hibernate事务管理器永远不会在出现错误时回滚两个数据库中的一个。例如,使用@Pani Dhakshnamurthy提到的ChainedTransactionManager可能会有所帮助,但本答案中未提及。