返回介绍

Java 帝国之宫廷内斗

发布于 2025-02-16 11:28:23 字数 5537 浏览 0 评论 0 收藏 0

1 JDBC 大臣

自从和东海之滨的数据库联合酋长国缔结了合作协议以后, IO 大臣就退居二线了。

他本来也想把 JDBC 也划归自己管理, 奈何国王头脑发热、竟然任命了新的 JDBC 大臣, 专门负责这一摊事儿。

JDBC 大臣经常在早朝上给国王吹风: “ 陛下, 我们的 JDBC 设计的非常好, 别看什么 Hibernate, Mybatis 是现在的事实标准, 他们底层都在用我们的 JDBC 接口。 ”

国王赞许地频频点头,似乎忘记了这是躲在角落中 IO 大臣的功绩。

IO 大臣咬牙切齿又无可奈何。

这天 JDBC 又在给国王安利关系数据库的好处: “陛下,这关系数据库相比于简单的文件系统有个巨大的好处,就是支持事务。”

听到 JDBC 大臣又在贬低自己负责的部门, IO 大臣怒火中烧。

国王问道:“什么是事务,要事务干嘛? ”

“我举个通俗的例子你就明白了, 假设 IO 大臣要给我转账 100 块钱, 他的数据库账户要扣掉 100 块, 我的账户要增加 100 块, 这就涉及到两个操作, 这两个操作要么全部完成,要么一个都不做,只有这样才能保证数据的一致性, 这就是一个事务。数据库联合酋长国有个对事务总结了 4 个特性: 原子性(Atomicity) ,一致性(Consistency), 隔离性(Isolation) , 持久性(Durability) , 简称 ACID, 要不我再给详细的解释下?”

国王连忙摆手:“不不不, 别拿这些细节烦我, 你就告诉我们的臣民怎么去使用就行了”

JDBC 大臣说: “这个很简单, 默认情况下我们的 JDBC 都会把对数据库的操作认为是一个事务, 当然臣民们也可以设置成手工的方式, 手工地提交和回滚事务。不管哪种方式,都是非常简单的 。”

国王说: “那就好, 爱卿辛苦了, 还有事吗? 有事启奏,无事退朝。”

2 密谋

IO 大臣回到家中,依然感觉火气难平, 招来幕僚商谈。

InputStream 说: “大人, 这 JDBC 大臣虽然猖狂, 我们却暂时拿他没办法, 现在都是 Web 时代, 哪个应用不用数据库啊? ”

“难道就让他这么猖獗下去? ”

InputReader 足智多谋: “我倒是有一计, 只是得等待时机。 ”

“什么时机?”

“你看今天 JDBC 那厮提到了事务, 但是这个事务只是在一个数据库中有用啊, 如果需要跨数据库怎么办? 比如我的账号存在数据库 A, 你的账号在数据库 B, 那转账的时候怎么办? 怎么实现什么 ACID ? ”

InputStream 表示不同意: “谁会这么傻, 把我们的账号信息放到两个数据库当中? ”

“这就是时候未到, 现在大部分的应用数据量都不大, 放到一个数据库中绰绰有余,等到数据量大到一定程度,势必要拆分数据库,就会出现跨数据库的事务, 到那个时候我们的机会就来了, 我们准备好解决方案, 参那厮一本, 不信扳不倒他!”

IO 大臣拍板: “好! 就这么办, 这事离不开数联酋(数据库联合酋长国)的支持,我和他们还有交情, 这就派人去,许以重金, 让他们继续和我们合作。”

在 IO 大臣密谋的同时, JDBC 大臣的家中却是觥筹交错、莺歌燕舞。

有识之士如 Connection 曾经向 JDBC 大臣提醒过要和数联酋搞好关系, 以便将来有什么不时之需。 可是处于巅峰的 JDBC 大臣哪能听得进去?

3 两阶段提交

InputReader 果然很有远见, 随着时间的流逝, Web 越来越发达, 帝国出现了很多巨型网站, 他们的各种数据果然是没法放到一个数据库中了,把大的业务系统查分成多个数据库势在必行, 当一个业务同时操作多个数据库的时候, 没有分布式事务是做不了的。

正在此时,一个秘密奏章被送到了国王的案头, 状告 JDBC 大臣因循守旧,面对大好的形式不与时俱进,对分布式事务漠不关心,毫无作为。

国王召集朝会,讨论分布式事务的问题, 他向 JDBC 大臣率先发难: “爱卿, 你听说过臣民们要求支持分布式事务吗?”

JDBC 大臣慌了: “这。。。 这好像是一撮刁民提的要求吧, 陛下不用理会。”

IO 大臣冷笑一声:“刁民? 我看是良民吧 ! 启奏陛下, 据臣所知,帝国有不下百个系统要求支持分布式事务,JDBC 大臣竟然连最基本的情况都不知道, 真是毫无作为。”

IO 大臣觉得稳操胜券,直接撕破了脸。

国王心里明白了几分, 他直接对 IO 大臣说: “爱卿,你说说该怎么办?”

“陛下,当年臣和数据库联合酋长国谈判的时候, 和他们建立了良好的交情。 前几天我宴请他们的时候,特别提及了这件事情。 Oracle 告诉臣,这很好办, 人家别的王国正在讨论实施两阶段提交的协议, 我们也可以参与进来。”

虽然 IO 大臣已经和数据库联合酋长国讨价还价了很久, 不知道花费了多少金钱,但还是不显山不漏水、很随意地说了出来。

JDBC 大臣一看 IO 大臣进入了自己的一亩三分地, 急忙问道: 什么是两阶段提交?

IO 大臣不屑地瞥了他一眼, 从袖子中拿出早就准备好的提议,双手向国王奉上。

国王哪里看得懂,扫了一眼就赐给望眼欲穿的 JDBC 大臣, 只见上面赫然写着:

两阶段提交协议

由于涉及到多个分布式的数据库, 我们特设一个全局的事务管理器,它来负责协调各个数据库的事务提交, 为了实现分布式事务,特设两个阶段:

阶段 1: 全局的事务管理器向各个数据库发出准备消息。 各个数据库需要在本地把一切都准备好,执行操作,锁住资源, 记录 redo/undo 日志, 但是并不提交, 总而言之,要进入一个时刻准备提交或回滚的状态, 然后向全局事务管理器报告是否准备好了。

阶段 2: 如果所有的数据库都报告说准备好了, 那全局的事务管理器就下命令: 提交, 这时候各个数据库才真正提交 , 由于之前已经万事具备,只欠东风,只需要快速完成本地提交即可;

如果有任何一个数据库报告说没准备好, 事务管理器就下命令: 放弃, 这时候各个数据库要执行回滚操作, 并且释放各种在阶段 1 锁住的资源。

JDBC 大臣也是行家,一看就明白了是怎么回事。阶段 1 就是让大家都准备好,阶段 2 就是迅速提交。

这是一个看起来很美的理想方案,但是他意识到其中有漏洞,自己的幕僚曾经告诫过:一旦涉及到分布式,事情就不会那么简单,任何地方都有失败的可能。

比如在第二阶段,那个事务管理器要是出了问题怎么办? 人家各个数据库还在等着你发命令呢? 你迟迟不发命令,大家都阻塞在那里,不知所措,到底是提交呢?还是不提交呢, 我这里还锁着资源呢, 迟迟不能释放,多耽误事啊 ! 

还是第二阶段,事务管理器发出的提交命令由于网络问题,数据库1收到了,数据库2没收到,这两个数据库就处于不一致状态了, 该怎么处理?

JDBC 大臣决心给 IO 大臣挖个坑:让你逞能 ! 让你给老子穿小鞋! 

他说:“ 陛下,IO 大臣不愧为设计过 JDBC 协议的股肱之臣, 臣才学疏浅,深为拜服,特奏请陛下恩准 IO 大臣再次出山和数据库联合酋长国设计出新协议, 来支持分布式事务。”

国王准奏。

4 JTA

IO 大臣满心狐疑, 不知道 JDBC 老头儿在给自己下什么药,回到府中和大家商量。

InputReader 眼看自己多年前的计策就要成功,颇为兴奋: “管它呢, 只要咱们把这个分布式事务的协议给制定好,JDBC 老儿就得下台了。”

“对,到时候我们就掌管文件, 网络,数据库,Java 帝国就是我们 IO 独大了” InputStream 开始畅想美好的未来,到时候自己估计至少从 5 品升为 4 品。

IO 大臣马上安排和数据库联合酋长国的谈判,由于之前良好的交情。 这一次协议很容易就达成了, IO 大臣给他起了一个很响亮的名字: Java Transaction API (简称 JTA)。

这个 JTA 规范用起来也比较简单, 只要获得一个 UserTransaction 就可以操作了,帝国的臣民们根本不用关系底层的协议细节:

经过国王的批准, JTA 正式推广。

可是令 IO 大臣万万没有想到的是, 国王在 JTA 发布的前夕, 亲切地召见了自己和另外一个不知名的官员, 国王关心地说:“爱卿,朕知道你很忙,掌管着网络和文件操作,为了给你减轻负担,朕决定任命一个新的 JTA 大臣来协助你!”

IO 大臣如同五雷轰顶,自己辛辛苦苦的工作完全被无视, 这到底是为什么?

他失魂落魄地回到府中, 好几天茶饭不思。

还是 InputReader 出来安慰了他: “这是陛下的帝王之术, 害怕我们一家坐大, 平衡了一下朝中力量。大人可以放宽心, 你看 JDBC 大臣也受到了打压,风光不再了。”

5 塞翁失马,焉知非福

JTA 并没有取得像 JDBC 那样的广泛应用, JDBC 大臣挖的那个坑现在终于露出了狰狞的面目。

只不过这个坑并没有让 IO 大臣掉进去, 新任的 JTA 大臣背了黑锅。

臣民的抗议声越来越多: 分布式事务伴随着大量节点的通信交换, 协调者要确定其他节点是否完成, 加上网络带来的超时,导致 JTA 性能低下, 在高并发和高性能的场景下举步维艰。

拜 IO 大臣的工作所赐, 现在数据库联合酋长国的各个部落都支持两阶段提交,很多应用服务器 Websphere , Weblogic 等都支持 JTA, 可是使用者确是寥寥无几, 都快成摆设了。

JTA 大臣每次上朝都战战兢兢, 他是个平庸之辈,虽然四处救火,但是无力解决根本的问题。

现在那些高并发的系统反而极力避免两阶段提交, 他们绕开 JTA 大臣, 直接找到了 IO 大臣诉苦:“大人,你带领着制定了 JTA, 但是这个标准太理想化,完全不符合实情啊! ”

IO 大臣说: “不会吧,这不是你们要求的吗, 用户 A 和 B 的账号分别在两个数据库, 当 A 给 B 转账 100 块的时候, 肯定得保证 A 扣掉 100, 然后 B 增加 100 啊。”

“这就是官府的想法, 总是想着让两个数据库保证实时的一致性(强一致性), 为了达到这个目标,JTA 付出的代价太高了。 我们现在不想这么干了。 我们可以忍受一段时间的不一致,只有最终一致就行。 比方说 A 给 B 转 100 元, A 中的钱已经扣除, 但是 B 中不会实时地增加,过段时间能保证增加就行了”

“最终一致性? 有点意思!” ,想到 Java 帝国的官方标准总是被臣民们所建立的事实标准所打败,敏锐的 IO 大臣立刻看到了背后的机遇, 他决定这一次要联合民间力量,再次反攻, 一举搞掉 JDBC 大臣和 JTA 大臣。

想到这里, IO 大臣得意地笑了......

(未完待续)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文