MURSIW 事务管理器
MURSIW 是一种传统的基于锁的事务管理器,其具体实现为一个简单的队列结构。值得注意的是,在使用 MURSIW 时,唯一支持的隔离级别为 MCO_SERIALIZABLE。此外,通过设定事务优先级或事务调度策略,可以对 MURSIW 的事务处理过程产生影响。
升级事务
在事务升级方面,由于 MURSIW 采用队列机制处理事务,当在 MCO_UPDATE 事务上下文中调用事务升级 API 时,该升级操作将确保成功执行。然而,若队列中已存在或正在运行 MCO_UPDATE 事务,则应用程序请求第二个 MCO_UPDATE 事务时,事务启动 API 将进入阻塞状态,直至第一个 MCO_UPDATE 事务完成(无论是提交还是回滚)。
为了更好地理解 MURSIW 事务管理器的内部逻辑,请参考以下场景:
场景 #1
如果存在一个 MCO_READ_ONLY 事务正在运行,且请求进行升级,那么该事务将立即被提升为 MCO_READ_WRITE,即便队列中还有另一个 MCO_READ_WRITE 事务。
场景 #2
如果有两个(或更多)MCO_READ_ONLY 事务正在运行,其中一个请求升级(调用 mco_trans_upgrade()),其在队列中的状态将更改为 UPDATE 并暂停,直到其他 MCO_READ_ONLY 事务提交或回滚,然后它将被提升为 MCO_READ_WRITE 并继续执行(即使队列中有一个或多个 MCO_READ_WRITE 事务)。
场景 #3
如果有两个(或更多)MCO_READ_ONLY 事务正在运行,并且其中两个(或更多)请求升级(调用 mco_trans_upgrade()),则第一个请求升级的事务将成功,而其他事务将失败。第一个事务在队列中的状态将更改为 UPDATE,并将被挂起,直到其他 MCO_READ_ONLY 事务提交或回滚,然后它将被提升为 MCO_READ_WRITE 并继续执行(即使队列中有一个或多个 MCO_READ_WRITE 事务)。
场景 #4
当启动 MCO_UPDATE 事务时,没有其他事务正在运行或在队列中。该事务进入队列并立即以 UPDATE 状态安排。任何其他事务(读取或写入)都将排队。当调用升级 API 时,队列中可能还有其他 MCO_READ_ONLY 或 MCO_READ_WRITE 事务,但 MCO_UPDATE 将立即提升为 MCO_READ_WRITE,即使在它之后进入队列的事务优先级更高。
场景 #5
当以 MCO_UPDATE 事务类型调用事务启动 API 时,如果队列中已存在状态为 UPDATE 的事务正在运行或等待处理,此时事务启动 API 将被阻塞,直到 MCO_UPDATE 事务以及队列中位于其前面的所有其他事务完成(提交或回滚),然后该事务将以 UPDATE 状态执行。
场景 #6
当针对类型为 MCO_READ_ONLY 的交易调用升级 API 时,如果队列中已存在状态为 UPDATE 的交易,则升级 API 将返回错误代码 MCO_E_UPGRADE_FAIL。
因此,MURSIW 的事务类型和并发性可以总结在以下表格中,其中 Y 表示此类事务可以并发运行,N 表示它们串行运行:
MCO_READ_ONLY | MCO_READ_WRITE | MCO_UPDATE* | |
---|---|---|---|
MCO_READ_ONLY | Y | N | Y |
MCO_READ_WRITE | N | N | N |
MCO_UPDATE | Y | N | N |
* 在调用事务开始 API 之后且在调用升级 API 之前;在调用升级 API 之后,其语义与 MCO_READ_WRITE 相同。
请注意,一个事务可能会读取、插入、更新或删除单个对象或多个对象,甚至数千个对象,这取决于应用程序的需求。在单个事务中处理对象块时,可能会出现这样的情况:一个对象被删除,但在提交事务之前再次访问了该对象。如果发生这种情况,读取(获取)或更新(放置)操作,或者任何其他访问,例如在游标中定位对象或生成对象的 XML,都将导致一个致命错误代码 MCO_ERR_OBJECT_HANDLE+N,其中 N 是源代码中检测到无效句柄的确切位置的行号。为了防止这种致命错误,C 应用程序可以调用函数 mco_is_object_deleted() 来确定对象是否在当前事务中已被删除。