应用层事务引擎设计概述

 应用层事务,是在应用层保证对数据的操作能够正确完整地执行的机制。

应用场景:

1 数据库重启:
应用在执行数据库存储过程时,数据库重启,连接丢失,应用层得到数据库连接断开的回复,不知道此事务是否执行完成。

2 网络抖动
网络抖动时,也会得到数据库连接丢失。尽管以后数据库会恢复,但是应用层得到执行失败的结果,却不能处理。

假设应用的执行在服务器是瞬间完成的,要么成功,要么失败。称为“原子事务假设”。

然后再针对复杂事务,假设其执行时间不可忽略,在事务执行的过程中,出现故障,或是代码异常,或是数据库重启,网络中断,导致事务的一部分成功,另一部分失败。这种称为“复合事务假设”。

很显然,复合事务假设相当复杂,也不易模拟重现,而且,也不能排除它发生的可能性,尽管这种概率看起来并不大。

原子事务假设

对超过多条数据的更改,都封装在存储过程中执行,在存储过程中使用数据库事务,以确保其原子性。且在存储过程中返回结果代码,供应用层判断。

应用层可以根据操作代码执行结果是否正确。如果结果不正确,则应根据不同的原因做出相应的处理。

1 代码错误/数据库异常
此类错误由偶然的代码逻辑错误,或者引入了偶然的非法数据。这种情况,无论如何都不会执行成功,就需要放弃这个事务,同时记录日志,反馈到开发环节去改进。

2 连接/网络 异常
异常在连接成功打开之后发生。如果连接无法成功打开,说明异常已经发生,则不能继续执行。
如果异常在连接打开之后发生,应用层不会得到正确的返回,无论存储过程执行成功与否。此时应用层需要执行数据检查,然而由于连接已经不能打开,则检查也无从谈起。
此时的处理方案是,把此事务序列化存储,同时中止一切其他事务的操作,直到网络恢复为止。

由上面的分析,得到应用层事务的需求如下:

1 事务应能序列化存储;不光存储事务数据,还能存储它的状态:未执行;失败需重试;失败已放弃;未知需检查;

2 日志:将由代码错误引起的失败事务的详细信息,记录下来,以供分析之用。

3 事务执行者(事务引擎)是全局的,当连接异常发生时,引擎将全局状态标记为不可用;同时引擎停止执行一切事务。

4 事务引擎,具有等待与检测连接是否可用的功能;当连接可用时,引擎恢复运行。

5 引擎恢复后,对存储的事务内容进行检查,逐条或并行执行。对于那些标记为“未知需检查”的事务,执行数据检查,如果检查通过则说明事务执行成功;否则重新执行此事务。

复合事务假设

复合事务,从表面上看来,也是一种原子事务,但它的内部,可能由多个其他的原子事务组合而成。

假设某复合事务 X ,由原子事务 A, B 组成,两者是顺序执行。

在 A 异常后,事务引擎会停止,同时检查A执行是否成功,如果 A 失败,则X需重新执行。 如果 X 成功,则应把B当成另一个紧急事务加入队列,等网络恢复后优先执行。

如果A的结果无法确认,则将 复合事务 X 标记为“需检查”,同时,检查点设置为A。这样,当网络恢复时,引擎会检查A的执行结果,再决定 如何 处理X。

如果 B 发生了代码异常,那么A的成功操作应撤销,然后放弃 X 的执行。

由上面分析,得到以下需求/结论:

1 复合事务,是原子事务的子类。

2 引擎能够区分复合事务与原子事务的区别。可以使用“状态模式”来实现多态。

3 引擎的内部队列,有优先级,可能不止有一个队列。

4 复合事务的组成者,要具备 在成功操作后 撤销的功能,这就引出了 “反向事务”。 如果 反事务也失败了呢? 引擎的设计可能 更麻烦了 ,头大, 暂时放弃这个吧。

其他问题

1 事务队列应持久化到磁盘上,或由第三方消息队列来管理。防止 应用崩溃后队列中的数据丢失。

2 实时性要求:事务引擎的多线程及同步问题。

3 目前的ORM并不支持事务,这是一种不够安全的做法。考虑到与现有系统的兼容,事务最好能做成 ORM 框架的一个扩展实现 。因此,事务引擎应是最低层接口,其上层有ORM封装和应用封装。

发表评论

电子邮件地址不会被公开。 必填项已用*标注