当前位置:  开发笔记 > 编程语言 > 正文

使用Spring和Hibernate在多个数据库中执行分布式事务的"最佳"方法是什么?

如何解决《使用Spring和Hibernate在多个数据库中执行分布式事务的"最佳"方法是什么?》经验,为你挑选了3个好方法。

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

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

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

该应用程序不在Java EE容器中 - 它由从shell脚本调用的静态启动程序类引导.启动器类实例化Application Context,然后在其中一个bean上调用方法.

围绕数据库更新放置事务性的"最佳"方法是什么?

我将"最好"的定义留给您,但我认为它应该是"易于设置","易于配置","便宜"和"易于打包和重新分发"的功能.自然FOSS会很好.



1> Aaron Digull..:

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

有些人会指向XA,但XA(或两阶段提交)是谎言(或市场营销).

想象一下:在第一阶段告诉XA经理它可以发送最终提交之后,与其中一个数据库的网络连接失败.怎么办?超时?这会让其他数据库损坏.回滚?两个问题:你无法回滚提交,你怎么知道第二个数据库发生了什么?成功提交数据后,网络连接可能失败,只有"成功"消息丢失了?

最好的方法是将数据复制到一个地方.使用允许您中止副本并随时继续使用的方案(例如,忽略您已有的数据或按ID排序选择并仅请求副本的记录> MAX(ID)).通过交易保护这一点.这不是问题,因为您只是从源读取数据,因此当事务因任何原因失败时,您可以忽略源数据库.因此,这是一个简单的旧单源事务.

复制数据后,在本地处理它.


@Falcon:那么如果网络在PREPARE和COMMIT之间失败会发生什么?或者其中一个服务器死了?"不可能发生"在现实中不可能发生.
分布式事务必须满足所有4个ACID属性.你怎么了?您描述的场景不可能发生,因为管理器彼此通信并且仅在所有参与节点交换"GO"时才提交.
不,他们没有被指示回滚,因为在这种情况下,一些节点已经提交.当崩溃的节点变得可用时,事务协调器会告诉它再次提交.由于节点在"准备"阶段响应积极,因此即使从崩溃中恢复,也需要能够"提交".
@Nicholas我发现只有那些通过解决这个标准产生的问题赚钱的公司才能广泛支持."消费者"(=不得不忍受此类解决方案的人)通常会尝试一次,然后寻找更好的解决方案.也就是说,我的回答在逻辑上是合理的.我的方法比XA简单得多,我可以证明它始终有效.XA更多的是承诺,而不是事实.

2> 小智..:

在您的上下文中设置事务管理器.Spring文档有例子,而且非常简单.然后当你想要执行一个事务时:

try { 
    TransactionTemplate tt = new TransactionTemplate(txManager);

    tt.execute(new TransactionCallbackWithoutResult(){
    protected void doInTransactionWithoutResult(
            TransactionStatus status) {
        updateDb1();
        updateDb2();
    }
} catch (TransactionException ex) {
    // handle 
}

有关更多示例,请参阅此信息: 使用Spring的XA事务


这个例子并没有真正回答这个问题,或者它甚至错误地回答了问题:OP提到他配置了两个Hibernate会话工厂,这需要两个独立的事务管理器.答案中的示例仅使用一个未指定更近的事务管理器.因此,使用单个Hibernate事务管理器永远不会在错误上回滚两个DB中的一个.例如,使用`ChainedTransactionManager`(如@Pani Dhakshnamurthy所述)可能有所帮助,但这个答案中没有提到.

3> skaffman..:

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

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

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

推荐阅读
赛亚兔备_393
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有