可序列化的初学者指南

804 阅读4分钟

简介

在这篇文章中,我们将看到可序列化是什么意思,它能提供什么保证。

关系型数据库系统提供了一个可序列化的隔离级别,应该提供事务的可序列化。然而,你很快就会看到,一些数据库甚至提供了严格的可序列化,这是可序列化和可线性化的结合。

串行执行

在解释Serializability的含义之前,让我们看看什么是Serial execution,因为Serializability与Serial execution非常不同。

串行执行提供了对共享资源的排他性访问,每次只有一个客户端,如下图所示。

Serial Execution

通过提供对共享资源的独占访问,可以防止数据异常,因为每个事务都会看到数据库处于前一个事务留下的一致状态。

有许多技术使用串行执行,最流行的是JavaScript、Node.js或Volt DB。

然而,有一个问题。根据阿姆达尔定律,并行化的程度与特定工作负载的Serial执行的百分比成反比。

因此,串行执行的扩展性很差;因此,它只限于数据存储在内存中的系统,而且每次执行需要的时间非常少。

并发冲突

绝大多数关系型数据库系统都通过多个连接提供并发访问。因此,在任何时候,都可能有多个事务在读写数据。

如果不强制执行Serializability,就会发生冲突。在数据库事务的背景下,这些冲突被称为现象或数据异常。

例如,下图向你展示了在没有Serializability的情况下可能发生的Lost Update异常现象

Lost Update Anomaly

如果你将Lost Update异常图与Serial执行图相比较,你会发现在Lost Update异常例子中,属于不同事务的读和写是交错进行的。

为了避免数据异常,事务日志应该对事务进行线性化处理,这样就不会出现属于不同事务的读写交错的情况。

可序列化

所以,为了避免冲突,我们必须不交织交易。虽然串行执行避免了事务交错,因为每个事务都有对数据库的独占访问权,但有一种方法我们可以在不牺牲并行性的情况下实现同样的目标。

而这个解决方案被称为Serializability。与串行执行不同,Serializability允许多个并发的转换运行,但有一个问题。其结果需要等同于串行执行。

因此,如果Alice和Bob都在运行两个并发事务,只有两种可能的串行执行结果。

  • Alice跟着Bob
  • 鲍勃跟着爱丽丝

如果事务日志中的语句遵循这种模式,那么结果就被称为可串行化。

如果有三个并发的事务,A、B和C,有3! = 6 可能的串行执行结果。顺序对于实现可序列化并不重要。唯一的约束是要得到一个串行的执行结果。

对于N个并发事务,有N! 可能的串行执行,每一个都提供一个适当的可串行的执行流程。

然而,如果事务流程既是可序列化的,又是可线性化的(操作是即时应用的),那么我们就会得到一个严格的可序列化的一致性模型。

Isolation Levels

可序列化的实现方式

有两种可能的方式来实现可序列化。

Oracle中的Serializable隔离级别实际上是Snapshot Isolation,虽然它可以防止许多异常现象,但它并不能防止所有可能的Write Skew现象

结论

序列化允许我们在不牺牲并行性的情况下防止并发冲突,就像串行执行那样。

只要结果与任何可能的串行执行相当,多个事务就可以成功提交,数据库系统可以使用锁或MVCC(多版本并发控制)机制来实现这一目标。