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

时间:2020-03-06 14:40:30  来源:igfitidea点击:

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

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

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

该应用程序不位于Java EE容器中,而是由从外壳程序脚本调用的静态启动器类引导的。启动器类实例化应用程序上下文,然后在其一个bean上调用一个方法。

围绕数据库更新进行事务处理的"最佳"方法是什么?

我将"最佳"的定义留给我们,但是我认为它应该具有"易于设置","易于配置","廉价"和"易于打包和重新分发"的功能。自然,FOSS会很好。

解决方案

在上下文中设置事务管理器。 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)与协调员对话。

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

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

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

有人会将我们指向XA,但XA(或者"两阶段提交")是一个谎言(或者市场说法)。

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

最好的方法是将数据复制到一个地方。使用允许我们中止副本并在任何时候继续进行操作的方案(例如,忽略已拥有的数据或者按ID排序选择,仅请求记录>副本的MAX(ID))。通过事务来保护它。这不是问题,因为我们仅从源中读取数据,所以当事务由于任何原因失败时,我们可以忽略源数据库。因此,这是一个普通的老式单源交易。

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