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

StackOverflow https://stackoverflow.com/questions/128377

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

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

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

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

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

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

有帮助吗?

解决方案

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

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

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

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

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

其他提示

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

try { 
    TransactionTemplate tt = new TransactionTemplate(txManager);

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

有关更多示例,请参阅此信息: 使用Spring进行XA交易

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

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

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

在这种情况下,您需要一个事务监视器(支持XA协议的服务器)并确保您的数据库也支持XA。大多数(所有?)J2EE服务器都内置了Transaction Monitor。如果你的代码不在J2EE服务器中运行,那么就有很多独立的替代品 - Atomicos,Bitronix等。

您可以尝试Spring ChainedTransactionManager - http://docs.spring.io/spring-data/commons/docs/1.6.2.RELEASE/api/org/springframework/data/transaction/ChainedTransactionManager.html 支持分布式db事务。这可能是XA的更好替代方案

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top