数据库事物

事物 Transaction 用于确保数据库的一致性。当需要更新多条(两条及以上)数据时,可以确保两次更新同时成功或同时失败;当数据被并发的读和修改时,可以确保读线程访问到完整的更新后数据或更新前数据。

事物特性

SQL 标准对事物提出了四个特性要求:

  • 原子性 Atomicity:一个事物必须被视为一个不可分割的最小工作单元,整个事物中的所有操作要么全部成功后提交,要么全部失败后回滚,不可能只执行其中一部分操作。
  • 一致性 Consistency:数据库总是从一个一致性的状态转移到另外一个。数据的一致性通常由业务逻辑定义,例如电商购买商品。用户下单需写订单记录表、扣减商品需更新库存表,这两步操作要么都完成、要么都失败。如果订单记录表有了新的记录,但库存表没有修改,就可以认为目前的数据不满足一致性。
  • 隔离性 Isolation:通常来说,一个事物所做的修改在最终提交以前对其他事物是不可见的。完全实现隔离性的代价太大,往往得不偿失,所以 SQL 标准提出了四种级别,下面详细介绍。
  • 持久性 Durability:一旦事物提交,其所做的修改就会永久保存到数据库中,换言之最终会写到磁盘上。

事物隔离级别

并发访问数据时,可能会出现以下三个问题:

  • 脏读 Dirty Read:一个事物即便没有提交,其中的修改在其他事物中也是可见的。
  • 不可重复读 Unrepeatableread:一个事物执行的过程中,另一个事物修改了数据库记录并且已提交,该事物可能两次读取到的记录不一致,即多次查询可能得到不同的结果,因此得名不可重复读。
  • 幻读 Phantom read:一个事物执行的过程中,另一个事物新增或删除了数据库记录并且已提交,并且该事物恰好执行了两次范围查询,第二次查询的结果和第一次相比可能多几条数据或少几条数据,好像发生了幻觉所以被称为幻读。

下面分别介绍四个级别。

未提交读 Read Uncommitted

在未提交读级别不能解决上述的任何问题,该级别下相当于没有隔离性,因此不会有人在生产环境中使用。

提交读 Read Committed

顾名思义,提交读是一个事物开始时,只能看到已提交的数据修改,这一级别解决了脏读问题,但还存在不可重复读和幻读问题。大多数数据库服务器的默认隔离界别是提交读。

可重复读 Repeatable Read

可重复读能够保证同一个事物中多次读取同样记录的结果是一直的,但依然无法解决幻读的问题,这一级别解决了脏读和不可重复读问题,但没有解决幻读。MySQL 默认的隔离级别是可重复读。

Innodb 引擎通过多版本并发控制 MVCC 机制,也能在可重复读级别中解决幻读问题。

可串行化 Serializable

可串行化是指每个事物都强制串行,没有并发问题时自然不会发生幻读的问题。可串行化级别下,事物中每个查询或修改都会在相关的每一行数据上加锁,有可能导致大量的超时和锁竞争。实际情况中很少会用到。