并发控制和事务管理
并发被定义为多个任务同时访问共享数据的能力。SmartEDB中的数据库并发控制是通过数据库事务实现的。SmartEDB事务管理器确保数据库事务并发执行,同时不违反数据完整性,并且事务遵循 ACID 原则。
传统上,数据库并发有两种模型:乐观并发和悲观并发。悲观并发控制基于这样的假设:数据修改操作很可能影响不同任务进行的任何读操作;数据库系统悲观地假设会发生冲突。在使用悲观并发控制时,SmartEDB的行为是使用锁,并在任何数据被修改时阻止对数据库的访问。
乐观并发控制基于这样的假设:数据修改不太可能(尽管有可能)干扰任何其他任务读取或修改数据。在使用乐观并发控制时,运行时的行为是使用版本控制,允许读操作看到修改发生之前的数据状态。
为了让开发人员能够最好地选择并发控制,SmartEDB提供了三个事务管理器,作为单独的库实现,这使得应用程序通过简单地与适当的库链接就可以轻松使用其中的一个:
- MURSIW(多读者单写者):一种传统的基于锁(悲观)的事务管理器,
- MVCC(多版本并发控制):一种乐观事务管理器,
- EXCL(排他):一次只有一个任务可以访问数据库进行读或写。
事务管理器在用户指南中有详细讨论。
MURSIW
MURSIW 是传统的基于锁的事务管理器,被实现为一个简单的队列。应用程序发起的事务被添加到一个基于事务优先级排序的队列中,在每个优先级内,按时间顺序排列。这种并发方式使 MURSIW 事务管理器能够简化锁定机制,消除由于资源消耗型复杂锁仲裁和死锁预防算法导致的开销。这种极其轻量级的事务管理器非常适用于许多内存数据库和并发事务较少的持久数据库,以及完全或主要为只读的数据库。
在事务队列的一个优先级段内,只读事务可以同时执行。每个写事务依次调度,并在其事务期间独占数据库。写事务的序列化对应用程序程序员是透明的。由于事务管理器是“轻量级”的,设计和实现得当的应用程序事务执行迅速,序列化不是性能问题。
想象一下事务队列中有以下排队的事务类型:

所有“A”组中的事务将并行执行。当这三个事务都完成后,将调度事务“B”。当“B”完成后,“C”组中的所有事务将被调度并并行执行。当所有“B”事务都完成后,将调度“D”事务。任何新启动的事务都将在“D”之后进入队列(当然要遵循事务优先级)。
MVCC
MVCC 事务管理器增强了应用程序的数据库并发管理选项。在 MVCC 模型中,在查询数据库时,每个事务看到的都是已提交数据的快照,而不管属于其他任务的任何进行中的事务。这可以保护事务不查看由于对同一组对象或索引的其他事务更新而可能导致的不一致数据,从而为每个事务提供事务隔离。MVCC 管理器允许应用程序在运行时设置事务隔离级别,以选择事务之间如何相互隔离。
锁定优化
SmartEDB使用两种同步原语 - 闩锁和锁。第一种(闩锁)是使用原子指令实现的轻量级锁。例如,它用于树索引来锁定分支。第二种(锁)是使用内核锁(如果可能,还会使用轻量级原子操作以提高性能)实现的全尺寸同步原语。一个锁用于 SmartEDB注册表和数据库头,但在事务处理期间应用的所有其他锁取决于事务管理器的选择:
- MVCC - 索引中有多个闩锁,事务处理中有多个闩锁/锁。
- MURSIW - 索引中无闩锁,事务处理中有多个闩锁/锁(但少于 MVCC)。
- EXCL - 索引中无闩锁,事务队列上有一个单一锁
对于单线程和单进程应用程序,可以通过使用 EXCLusive 事务管理器和/或“空心”同步实现来完全消除闩锁和锁。(提供了一个“空心”同步实现的示例,该示例不进行内核调用、原子操作或自旋锁,作为自定义用户定义同步的模板。)
开发人员可以通过选择事务管理器和同步实现库来完全选择事务管理器和锁的实现。根据应用程序的特点,很可能在 MURSIW 和 MVCC 之间进行选择。对于大多数为只读事务且偶尔有更新的应用程序,MURSIW 可能是最佳选择。如果同时有相对较多的并发进程/线程试图修改数据库,那么 MVCC 可能是更好的选择。
可以通过简单地链接适当的库在事务管理器之间进行试验。不需要更改应用程序代码(除非最终选择 MVCC 时要处理冲突错误)。
请参阅用户指南页面以获取进一步的解释和事务管理器实现的详细信息。