例如,LevelDB不支持多语句事务。我在某个地方读到,您必须在"事务层"中处理这些问题。
该层需要做些什么才能将事务支持添加到不支持事务的较低级别库中?
定义事务的方法多种多样,实现事务的方法也多种多样。事务的一个常见属性是它是ACID:
- 原子性-要么全有要么全无。数据库事务的所有任务都必须完成;如果由于任何可能的原因而不完整,则必须中止数据库事务
- 一致性-可序列化性和完整性。在数据库事务之前和之后,数据库必须处于一致或合法状态。这意味着数据库事务不能破坏数据库完整性约束
- 隔离在数据库事务执行期间使用的数据在执行完成之前不得由另一个数据库事务使用。因此,在事务成功提交之前,不完整事务的部分结果不能用于其他事务。这也意味着事务的执行不受其他并发事务的数据库操作的影响
- 持久性即使在事务完成后发生系统故障,事务的所有数据库修改都将是永久性的
一笔交易可能有几种状态:
- 活动状态:它分为两个阶段。初始阶段:数据库事务处于该阶段,同时开始执行其语句。部分提交阶段:数据库事务在执行其最终语句时进入该阶段。在这个阶段,数据库事务已经完成了执行,但事务仍然有可能被中止,因为执行的输出可能暂时保留在主内存中——类似硬件故障的事件可能会擦除输出
- 失败状态:当数据库事务由于硬件或程序错误而无法继续正常执行时,它将进入失败状态)
- 中止状态:如果DBMS确定数据库事务失败,则数据库事务进入中止状态。中止的事务必须对数据库没有影响,因此它对数据库所做的任何更改都必须撤消,或者在技术上回滚。回滚中止的事务后,数据库将返回到其一致状态。DBMS的恢复方案负责管理事务中止
- 已提交状态:数据库事务在成功完成执行后,当有足够的信息写入磁盘时,它将进入已提交状态。在这种状态下,太多的信息被写入磁盘,事务产生的效果无法通过中止来撤消;即使发生系统故障,也可以在系统重新启动时重新创建提交事务所做的更改
LevelDB不支持事务,但是它有一些ACID属性:
- 批处理写入是原子的
- 一致性取决于您
- 隔离支持有限
- 耐久性是一个可配置的选项
所以。。。回到你的问题:
问:
该层需要做些什么才能将事务支持添加到不支持事务的较低级别库中?
A:这取决于您如何定义事务。如果你用上面提到的属性定义了一个事务,并且你希望你的事务是ACID,那么你必须弄清楚这在LevelDB中是否可行(大多数ACID属性都是集成的),然后你必须围绕LevelDB编写一个包装器,确保事务的状态得到正确维护。然而,我不完全确定单独的包装器是否能做到这一点,因此您可能必须实际获取源代码并将其修改为真正支持事务。
如果您的数据库是单线程的,您可以执行以下操作:
-
使用leveldb批处理功能:不要覆盖旧密钥,而是创建一个新密钥。同时记录密钥的旧值和新值。
-
如果此时数据库崩溃,请查找日志记录,并通过将事务中的键重述为其旧值来回滚事务。删除日志以完成回滚。
-
如果事务已提交,请删除旧密钥并删除日志条目以完成提交。
然后您就有了一个使用多个版本的单线程键/值存储的事务。
如果数据库是多线程的,则必须使用MVCC(请参阅Yahoo的Omid、PostgreSQL、Wiredtiger、bsddb…)和类似Precisly Serializable Snapshot Isolation(PSSI)的东西。