事务

事务就是一组原子性的 SQL 操作,事务中的语句,要么全部执行成功,要么全部执行失败。

事务正确执行的四个要素(ACID)

  • 原子性(atomicity)
  • 一致性(consistency)
  • 隔离性(isolation)
  • 持久性(durability)

原子性

一个事务内的一组 SQL 语句被视为一个不可分割的单元,事务中的语句,要么全部执行成功,要么全部执行失败。

一致性

数据库总是从一个一致性的状态转移到另一个一致性的状态。

应用系统从一个正确的状态到另一个正确的状态,而 ACID 就是说事务能够通过 AID 来保证这个 C 的过程。C 是目的, AID 都是手段。

如何理解数据库事务中的一致性的概念? - 孟波的回答 - 知乎 https://www.zhihu.com/question/31346392/answer/362597203

隔离性

“通常来说”,一个事务所做的修改在提交之前,对其他事务是不可见的。

持久性

事务一旦提交,其所做的修改就会保存到数据库中,此时即使系统崩溃,修改的数据也不会丢失。

Note: redo log 和 binlog

事务现象

执行事务时可能会出现三个特别的现象:

  • 脏读:一个事务可以读取到其他事务未提交的数据。
  • 不可重复读:一个事务内,执行两次相同的查询,得到的数据不一样。(特指列上的数据不一样)
  • 幻读:一个事务内,查询相同范围的数据,得到的记录数一样,这样产生幻影行的现象。

隔离级别

MySQL 支持四种隔离级别:

  • read uncommitted(读未提交)
  • read committed(读提交)
  • repeatable read(可重复读)
  • serializable(串行化)

read uncommitted(读未提交)

一个事务可以读取到其他事务未提交的数据。

read committed(读提交)

一个事务提交之前,所做的修改对其他事务不可见。但是由此会产生不可重复读的问题。

repeatable read(可重复读)

解决了不可重复读的问题,一个事务内,执行两次相同的查询,得到的数据一样。

通过多版本并发控制(MVCC)解决了幻读的问题。

rr 是 MySQL 的默认隔离级别。

serializable(串行化)

这个级别下,强制事务串行执行,会在读取的每一行数据上都加锁,所以可能导致大量的超时和锁争用的问题。

图片来自《高性能 MySQL》:

其他

查看隔离级别:

1
2
3
4
5
6
7
mysql> show global variables like '%tx_iso%';

+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| tx_isolation | REPEATABLE-READ |
+---------------+-----------------+

设置隔离级别:

1
mysql> set transaction isolation level read committed;

支持事务的引擎:

  • InnoDB
  • NDB Cluster

多版本并发控制

MySQL 的事务型存储引擎基于并发性能的考虑实现了 MVCC。MVCC 是行级锁的一个变种,但是在很多情况下避免了加锁操作,开销更低。

MVCC 的实现,是通过保存数据在某个时间点的快照来实现的。

InnoDB 的 MVCC,是通过在每行记录后面保存两个隐藏的列来实现的。一个列保存了行的创建时间,另一个列保存行的过期时间(或删除时间)。不是具体的时间值,而是版本号。每开始一个新的事务,系统版本号会自动递增,事务开始时刻的系统版本号会作为事务的版本号,用来和查询到的每行记录的版本号进行比较。

MVCC 只在 repeatable read 和 read committed 隔离级别下工作。