35

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

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

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

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

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

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

4

5 回答 5

41

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

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

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

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

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

于 2009-05-20T11:38:48.053 回答
8

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

try { 
    TransactionTemplate tt = new TransactionTemplate(txManager);

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

有关更多示例和信息,请参阅: XA transactions using Spring

于 2008-09-24T17:20:28.883 回答
5

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

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

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

于 2008-09-28T12:11:20.050 回答
3

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

于 2008-12-28T17:15:07.247 回答
3

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

于 2014-06-12T00:08:28.850 回答