- 原文地址:Distributed transactions in Spring, with and without XA - Part III
- 原文做者:David Syer
- 译文出自:掘金翻译计划
- 本文永久连接:github.com/xitu/gold-m…
- 译者:radialine
- 校对者:kezhenxu94
示例中的 ChainedTransactionManager
具备简单的优势:它不用为可用的扩展和优化费心。另外一种方法是在第二个资源加入时,使用 Spring 中的 TransactionSychronization
API 为当前事务注册一个回调。这是 best-jms-db
示例中的方法,其中关键特性是 TransactionAwareConnectionFactory
与 DataSourceTransactionManager
的组合。这种特殊状况能够扩展泛化到使用 TransactionSynchronizationManager
的非 JMS 资源上。优势是,原则上只有加入该事务的那些资源将被登记,而不是链中的全部资源。然而,配置仍然须要知道潜在事务中的参与者对应于哪些资源。html
此外,Spring 工程团队正在为 Spring Core 考虑开发「Best Efforts 1PC 事务管理器」功能。若是你喜欢该模式,而且但愿在 Spring 中看到对它的明确和更透明的支持,你能够在这个 JIRA 问题中投票。前端
非事务访问模式在某种特殊的业务流程中才有意义。这里是指,有时你须要访问的资源是边缘的,不须要在事务中。例如,你可能须要向审计表中插入一行,该行与业务事务是否成功无关,它只是记录了尝试作某事。更常见的是,人们高估了他们须要对一个资源进行读写更改的程度,每每只读访问就足够了。或者写操做能够被在更细粒度上加以控制,使得在写操做中出现错误时,错误能够被考虑或忽略。java
在这些状况下,保持在事务以外的资源可能实际上具备它本身的事务,可是它不与正在发生的任何事务同步。若是你使用 Spring,则主要事务由 PlatformTransactionManager
驱动,边缘资源多是从不禁事务管理器控制的数据库「链接」从「数据源」获取。全部这一切都发生在每一个访问边缘资源的默认设置是 autoCommit = true
时。读操做不会看到在另外一个未提交的事务中同时发生的更新(假设有合理的默认隔离级别),可是写操做的效果一般会被其余参与者当即看到。android
这种模式须要更仔细的分析和更多设计业务流程的信心,但它不是彻底不一样于 Best Efforts 1PC。当出现任何问题,提供补偿事务的通用服务对于大多数项目来讲是不现实的。可是简单的使用状况涉及幂等的、只执行一个写操做(可能屡次读)的服务并不罕见。这些是非事务性情境的理想状况。ios
最后一个模式是一个反模式。它每每出如今开发人员不了解分布式事务或不知道他们已经实现了一个分布式事务的状况下。若是没有显式调用底层资源的事务 API,你不能只是假设全部的资源都加入一个事务。若是你使用除 JtaTransactionManager
以外的 Spring 事务管理器,就会有一个事务资源依附到这个模式。该事务管理器将用于使用 Spring 声明性事务管理功能(如 @Transactional
)来拦截方法执行。不能指望在同一事务中登记其余资源。一般的结果是正常状况下一切没有问题,但只要有一个异常,用户会发现其中一个资源没有回滚。致使此问题的典型错误是使用 DataSourceTransactionManager
和使用 Hibernate 来实现仓库。git
我将经过分析这些模式的利弊得出结论,帮助你了解如何在它们之间作出决定。第一步是确认你有一个须要分布式事务的系统。一个必要的(但不是充分的)条件是存在具备多于一个事务资源的单个进程;一个充分的条件是这些资源在单个用例中一块儿使用,一般由对你的架构中的服务级别的调用驱动。github
若是你尚未分辨出分布式事务,你可能已经实现了飞行之翼模式。早晚你会看到应该已回滚但并无回滚的数据。可能在真实的错误发生好久后你才能看到所形成的影响,这时已经很难追溯回失败的源头。开发人员可能会不当心使用飞行之翼模式,由于他们认为 XA 已经在发挥做用,但实际上没有配置基础资源来参与事务。我曾经在一个项目上工做,其中数据库已被另外一个组安装,而且在安装过程当中关闭了 XA 支持。系统运行了好几个月,而后奇怪的错误开始渗透到业务流程中。诊断这个问题花了很长时间。spring
若是你的混合资源用例很简单,能够负担得起分析和重构,那么非事务资源模式多是一种选项。当其中一个资源主要是读取,写入操做能够经过对重复项的检查来保护时,这种模式最有效。即便在失败以后,非事务性资源中的数据也必须在业务中有意义。审核、版本控制和日志记录信息一般适用于此类别。在这个模式中,失败将是相对常见的(任什么时候候都有可能发生事务回滚),但你能够相信这个没有反作用。数据库
Best Efforts 1PC 适用于要求失败率低,且不但愿有像 2PC 那么大的开销的系统。选择这个模式带来的性能提高是很显著的。它的设置比非事务性资源更为棘手,但它不须要那么多的分析,而且用于更通用的数据类型。绝对的数据一致性要求业务处理对「外部」资源(除第一次之外的任一次提交)都是幂等的。消息驱动的数据库更新是一个完美的例子,Spring 对它已经有至关好的支持。更不常见的状况须要一些额外的框架代码(这些框架代码可能最终会是 Spring 的一部分)。后端
共享资源模式很是适用于特殊状况,一般涉及两个特定类型和平台的资源(例如 ActiveMQ 与任何 RDBMS 或 Oracle AQ 与 Oracle 数据库位于同一位置)。这个模式的优势是极强的鲁棒性和卓越的性能。
样例代码更新
因为 Spring 版本的新版本和其余组件的发布,本文提供的示例代码将不可避免地过期。请参阅 Spring 社区网站以访问做者的最新代码,以及 Spring Framework 和相关组件的最新版本。
Full XA with 2PC 是通用的,而且老是有最高的置信度、最强的保护以防止在使用多个不一样资源的状况下发生故障。缺点是,这个模式很昂贵,由于协议规定了额外的 I/O(但不要写,直到你尝试它),还须要特殊用途的平台。有开源 JTA 实现了这种模式,能够提供摆脱应用程序服务器的方法,但许多开发人员仍然认为这种方式是次优的。固然,更多人没有花时间思考他们系统中的事务边界就选择了使用使用 JTA 和 XA。至少若是他们使用 Spring,他们的业务逻辑就不须要知道事务是如何被处理的,所以能够延迟平台选择。
Dr. David Syer 是 SpringSource 的首席顾问,常驻英国。他是 Spring Batch 项目的创始人和首席工程师,Spring Batch 是一个用于构建和配置离线和批处理应用程序的开源框架。他常常主持关于企业 Java 和行业评论员的会议。最近的出版物能够在 The Server Side, InfoQ 和 SpringSource 博客找到。
javax.transaction
的 JTA 和 XAResource
的知识。若是发现译文存在错误或其余须要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可得到相应奖励积分。文章开头的 本文永久连接 即为本文在 GitHub 上的 MarkDown 连接。
掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 Android、iOS、前端、后端、区块链、产品、设计、人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划、官方微博、知乎专栏。