数据库中的事务隔离

在使用数据库时,当我们在两个事务中分别对同一块数据进行读写操作时会怎样呢?

Published @ Apr 23, 2016

今天看书的过程中看到讲并发控制的章节,突然想到我一直想搞清楚却没搞清楚的数据库事务间的并发控制是怎样的。于是就 Google 了一下,下面记录下来。

定义

首先,数据库事务的四个特性 ACID 从维基百科上抄下来如下:

  1. 原子性(atomicity):一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
  2. 一致性(consistency):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
  3. 隔离性(isolation):数据库允许多个并发事务同时对齐数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
  4. 持久性(durability):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

我现在主要关注的就是其隔离性,即当我们在两个独立的事务中分别对同一块数据进行读写操作时会怎样呢?

SQL 标准用三个需要在并行事务之前避免的现象,定义了四个事务隔离级别。这三个现象是:

  1. 脏读(dirty reads):一个事务读取了另一个未提交的并行事务写的数据。
  2. 不可重复读(non-repeatable reads):一个事务重新读取前面读取过的数据, 发现该数据已经被另一个已提交的事务修改过。
  3. 幻读(phantom read):一个事务重新执行一个查询,返回一套符合查询条件的行, 发现这些行因为其他最近提交的事务而发生了改变。

四个隔离级别定义如下:

隔离级别 脏读 不可重复读 幻读
读未提交(Read uncommitted) 可能 可能 可能
读已提交(Read committed) 不可能 可能 可能
可重复读(Repeatable read) 不可能 不可能 可能
可串行化(Serializable ) 不可能 不可能 不可能

各数据库的实现情况

既然 SQL 标准定义了 4 个级别,那么各个数据库的实现可能都有所不同,这里给出几个常用数据库的情况。

数据库 读未提交 读已提交 可重复读 可串行化
PostgreSQL - 默认 - 可选
MySQL/InnoDB 可选 可选 默认 可选
Sqlite 可选 - - 默认

上表中-表示未实现

PostgreSQL 对于两种隔离级别的具体表现细节在文档中已经讲的很清楚了

参考

  1. 维基百科 ACID
  2. PostgreSQL 文档
  3. Sqlite 文档
  4. Innodb中的事务隔离级别和锁的关系
END