简体   繁体   English

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

[英]What is the 'best' way to do distributed transactions across multiple databases using Spring and Hibernate

I have an application - more like a utility - that sits in a corner and updates two different databases periodically. 我有一个应用程序 - 更像是一个实用程序 - 位于角落并定期更新两个不同的数据库。

It is a little standalone app that has been built with a Spring Application Context. 它是一个使用Spring Application Context构建的小型独立应用程序。 The context has two Hibernate Session Factories configured in it, in turn using Commons DBCP data sources configured in Spring. 上下文中配置了两个Hibernate会话工厂,依次使用Spring中配置的Commons DBCP数据源。

Currently there is no transaction management, but I would like to add some. 目前没有交易管理,但我想补充一些。 The update to one database depends on a successful update to the other. 对一个数据库的更新取决于对另一个数据库的成功更新。

The app does not sit in a Java EE container - it is bootstrapped by a static launcher class called from a shell script. 该应用程序不在Java EE容器中 - 它由从shell脚本调用的静态启动程序类引导。 The launcher class instantiates the Application Context and then invokes a method on one of its beans. 启动器类实例化Application Context,然后在其中一个bean上调用方法。

What is the 'best' way to put transactionality around the database updates? 围绕数据库更新放置事务性的“最佳”方法是什么?

I will leave the definition of 'best' to you, but I think it should be some function of 'easy to set up', 'easy to configure', 'inexpensive', and 'easy to package and redistribute'. 我将“最好”的定义留给您,但我认为它应该是“易于设置”,“易于配置”,“便宜”和“易于打包和重新分发”的功能。 Naturally FOSS would be good. 自然FOSS会很好。

The best way to distribute transactions over more than one database is: Don't. 在多个数据库上分发事务的最佳方法是:不要。

Some people will point you to XA but XA (or Two Phase Commit) is a lie (or marketese). 有些人会指向XA,但XA(或两阶段提交)是谎言(或市场营销)。

Imagine: After the first phase have told the XA manager that it can send the final commit, the network connection to one of the databases fails. 想象一下:在第一阶段告诉XA经理它可以发送最终提交之后,与其中一个数据库的网络连接失败。 Now what? 怎么办? Timeout? 超时? That would leave the other database corrupt. 这会让其他数据库损坏。 Rollback? 回滚? Two problems: You can't roll back a commit and how do you know what happened to the second database? 两个问题:你无法回滚提交,你怎么知道第二个数据库发生了什么? Maybe the network connection failed after it successfully committed the data and only the "success" message was lost? 成功提交数据后,网络连接可能失败,只有“成功”消息丢失了?

The best way is to copy the data in a single place. 最好的方法是将数据复制到一个地方。 Use a scheme which allows you to abort the copy and continue it at any time (for example, ignore data which you already have or order the select by ID and request only records > MAX(ID) of your copy). 使用允许您中止副本并随时继续使用的方案(例如,忽略您已有的数据或按ID排序选择并仅请求副本的记录> MAX(ID))。 Protect this with a transaction. 通过交易保护这一点。 This is not a problem since you're only reading data from the source, so when the transaction fails for any reason, you can ignore the source database. 这不是问题,因为您只是从源读取数据,因此当事务因任何原因失败时,您可以忽略源数据库。 Therefore, this is a plain old single source transaction. 因此,这是一个简单的旧单源事务。

After you have copied the data, process it locally. 复制数据后,在本地处理它。

Setup a transaction manager in your context. 在您的上下文中设置事务管理器。 Spring docs have examples, and it is very simple. Spring文档有例子,而且非常简单。 Then when you want to execute a transaction: 然后当你想要执行一个事务时:

try { 
    TransactionTemplate tt = new TransactionTemplate(txManager);

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

For more examples, and information perhaps look at this: XA transactions using Spring 有关更多示例,请参阅此信息: 使用Spring的XA事务

When you say "two different databases", do you mean different database servers, or two different schemas within the same DB server? 当您说“两个不同的数据库”时,您是指不同的数据库服务器,还是同一个数据库服务器中的两个不同的模式?

If the former, then if you want full transactionality, then you need the XA transaction API, which provides full two-phase commit. 如果是前者,那么如果你想要完全的事务性,那么你需要XA事务API,它提供完整的两阶段提交。 But more importantly, you also need a transaction coordinator/monitor which manages transaction propagation between the different database systems. 但更重要的是,您还需要一个事务协调器/监视器来管理不同数据库系统之间的事务传播。 This is part of JavaEE spec, and a pretty rarefied part of it at that. 这是JavaEE规范的一部分,也是其中非常罕见的一部分。 The TX coordinator itself is a complex piece of software. TX协调器本身就是一个复杂的软件。 Your application software (via Spring, if you so wish) talks to the coordinator. 您的应用程序软件(通过Spring,如果您愿意)与协调员交谈。

If, however, you just mean two databases within the same DB server, then vanilla JDBC transactions should work just fine, just perform your operations against both databases within a single transaction. 但是,如果您只是指同一个数据库服务器中的两个数据库,那么vanilla JDBC事务应该可以正常工作,只需在单个事务中对两个数据库执行操作。

You could try Spring ChainedTransactionManager - http://docs.spring.io/spring-data/commons/docs/1.6.2.RELEASE/api/org/springframework/data/transaction/ChainedTransactionManager.html that supports distributed db transaction. 您可以尝试Spring ChainedTransactionManager - http://docs.spring.io/spring-data/commons/docs/1.6.2.RELEASE/api/org/springframework/data/transaction/ChainedTransactionManager.html ,它支持分布式数据库事务。 This could be a better alternative to XA 这可能是XA的更好替代方案

In this case you would need a Transaction Monitor (server supporting XA protocol) and make sure your databases supports XA also. 在这种情况下,您需要一个事务监视器(支持XA协议的服务器)并确保您的数据库也支持XA。 Most (all?) J2EE servers comes with Transaction Monitor built in. If your code is running not in J2EE server then there are bunch of standalone alternatives - Atomicos, Bitronix, etc. 大多数(所有?)J2EE服务器内置了事务监视器。如果您的代码不在J2EE服务器中运行,那么有许多独立的替代品 - Atomicos,Bitronix等。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM