什么是“最好的”? 使用 Spring 和 Hibernate 跨多个数据库进行分布式事务的方法
我有一个应用程序 - 更像是一个实用程序 - 位于角落并定期更新两个不同的数据库。
它是一个使用 Spring 应用程序上下文构建的小型独立应用程序。 该上下文中配置了两个 Hibernate 会话工厂,依次使用 Spring 中配置的 Commons DBCP 数据源。
目前还没有事务管理,但我想添加一些。 一个数据库的更新取决于另一个数据库的成功更新。
该应用程序并不位于 Java EE 容器中 - 它由从 shell 脚本调用的静态启动器类引导。 启动器类实例化应用程序上下文,然后调用其 bean 之一的方法。
围绕数据库更新进行事务处理的“最佳”方法是什么?
我将把“最好”的定义留给你,但我认为它应该是“易于设置”、“易于配置”、“便宜”和“易于打包和重新分发”的功能。 FOSS 自然是好的。
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. The context has two Hibernate Session Factories configured in it, in turn using Commons DBCP data sources configured in Spring.
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. The launcher class instantiates the Application Context and then invokes a method on one of its beans.
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
在多个数据库上分发事务的最佳方法是: 不要。
有些人会向您推荐 XA,但 XA(或两阶段提交)是一个谎言(或市场术语)。
想象一下:在第一阶段告诉 XA 管理器它可以发送最终提交后,与其中一个数据库的网络连接失败。 怎么办? 暂停? 这会使另一个数据库损坏。 回滚? 两个问题:您无法回滚提交以及您如何知道第二个数据库发生了什么? 也许在成功提交数据后网络连接失败,只丢失了“成功”消息?
最好的方法是将数据复制到一个地方。 使用允许您中止复制并随时继续复制的方案(例如,忽略您已有的数据或按 ID 排序选择并仅请求副本的记录 > MAX(ID))。 通过交易来保护这一点。 这不是问题,因为您只从源读取数据,因此当事务因任何原因失败时,您可以忽略源数据库。 因此,这是一个普通的单一来源交易。
复制数据后,在本地进行处理。
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).
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. 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). 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.
在您的上下文中设置事务管理器。 Spring 文档有例子,而且非常简单。 然后,当您想要执行交易时:
有关更多示例和信息,也许可以看一下:
使用 Spring 的 XA 事务
Setup a transaction manager in your context. Spring docs have examples, and it is very simple. Then when you want to execute a transaction:
For more examples, and information perhaps look at this:
XA transactions using Spring
当您说“两个不同的数据库”时,您是指不同的数据库服务器,还是同一数据库服务器内的两个不同模式?
如果是前者,那么如果您想要完整的事务性,那么您需要 XA 事务 API,它提供完整的两阶段提交。 但更重要的是,您还需要一个事务协调器/监视器来管理不同数据库系统之间的事务传播。 这是 JavaEE 规范的一部分,而且是其中非常稀有的一部分。 TX 协调器本身是一个复杂的软件。 您的应用程序软件(如果您愿意,可以通过 Spring)与协调器进行通信。
但是,如果您只是指同一数据库服务器中的两个数据库,那么普通 JDBC 事务应该可以正常工作,只需在单个事务中对两个数据库执行操作即可。
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. 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. The TX coordinator itself is a complex piece of software. Your application software (via Spring, if you so wish) talks to the coordinator.
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.
在这种情况下,您需要一个事务监视器(支持 XA 协议的服务器)并确保您的数据库也支持 XA。 大多数(全部?)J2EE 服务器都内置了事务监视器。如果您的代码不在 J2EE 服务器中运行,那么有很多独立的替代方案 - Atomicos、Bitronix 等。
In this case you would need a Transaction Monitor (server supporting XA protocol) and make sure your databases supports XA also. 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.
您可以尝试 Spring ChainedTransactionManager - http://docs.spring.io/spring-data/commons/docs/1.6.2.RELEASE/api/org/springframework/data/transaction/ChainedTransactionManager.html 支持分布式数据库交易。 这可能是 XA 的更好替代方案
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. This could be a better alternative to XA
对于那些建议可以消除对两阶段提交的担忧的人,因为它在实践中广泛使用,我建议看看这个: https://en.wikipedia.org/wiki/Two-phase_commit_protocol。 2PC 文章底部有一个链接,指向关于三阶段提交的文章(!)
3PC 上文章的一些摘录:
总结一下:
For those suggesting concerns with two-phase commit can be waved away because it's widely used in practice, I suggest looking at this: https://en.wikipedia.org/wiki/Two-phase_commit_protocol. There's a link at the bottom of the 2PC article to an article on three-phase commit(!)
Some excerpts from the article on 3PC:
To summarize: