使用Spring和Hibernate跨多个数据库进行分布式事务的“最佳”方式是什么?
我有一个应用程序 – 更像是一个实用程序 – 位于一个angular落,并定期更新两个不同的数据库。
这是一个有点独立的应用程序,已经build立了一个Spring应用程序上下文。 上下文中configuration了两个Hibernate Session Factories,然后使用Spring中configuration的Commons DBCP数据源。
目前没有交易pipe理,但是我想补充一些。 对一个数据库的更新取决于对另一个数据库的成功更新。
该应用程序不在Java EE容器中 – 它由从shell脚本调用的静态启动器类引导。 启动器类实例化应用程序上下文,然后在其一个bean上调用一个方法。
在数据库更新中使用事务性的“最佳”方法是什么?
我会把“最好”的定义留给你,但我认为它应该是“容易设置”,“容易configuration”,“便宜”和“容易打包和重新分配”等function。 自然,FOSS会很好。
通过多个数据库分配事务的最佳方式是:不要。
有些人会把你指向XA,但XA(或两阶段提交)是谎言(或市场人)。
想象一下:在第一阶段告诉XA经理它可以发送最终提交之后,到其中一个数据库的networking连接失败。 怎么办? 时间到? 这将使其他数据库损坏。 回滚? 两个问题:你不能回滚一个提交,你怎么知道第二个数据库发生了什么? 也许networking连接成功提交数据后失败,只有“成功”消息丢失了?
最好的方法是将数据复制到一个地方。 使用允许您放弃副本并在任何时间继续它的scheme(例如,忽略您已有的数据或通过ID命令select并请求您的副本的logging> MAX(ID))的scheme。 用交易保护这一点。 这不是问题,因为您只是从源读取数据,所以当事务因任何原因失败时,您可以忽略源数据库。 因此,这是一个普通的单一来源交易。
在复制数据之后,在本地处理它。
在您的上下文中设置事务pipe理器。 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,它提供了完整的两阶段提交。 但更重要的是,您还需要一个事务协调器/监视器来pipe理不同数据库系统之间的事务传播。 这是JavaEE规范的一部分,在这方面也是相当稀less的一部分。 TX协调器本身是一个复杂的软件。 你的应用软件(通过Spring,如果你愿意的话)与协调人谈话。
但是,如果你只是指同一个数据库服务器中的两个数据库,那么vanilla JDBC事务应该可以正常工作,只需要在一个事务中对两个数据库执行操作。
你可以尝试Spring ChainedTransactionManager – http://docs.spring.io/spring-data/commons/docs/1.6.2.RELEASE/api/org/springframework/data/transaction/ChainedTransactionManager.html ,它支持分布式数据库事务。 这可能是XA更好的select
在这种情况下,您需要一个事务监视器(支持XA协议的服务器),并确保您的数据库也支持XA。 大多数(所有的)J2EE服务器都内置了Transaction Monitor。如果你的代码不在J2EE服务器上运行,那么有很多独立的select – Atomicos,Bitronix等等。