MySQL 数据库隔离级别

事务特性(ACID)

原子性(atomicity)

事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。

一致性(consistency)

事务操作前和操作后都必须满足业务规则约束。比如说 A 向 B 转账,转账前和转账后 AB 两个账户的总金额必须是一致的。不可能 A 扣了钱,B 却没收到钱。

隔离性(isolation)

同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。隔离性可以防止事务并发执行时由于交叉执行导致数据不一致的问题。

持久性(durability)

一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的。接下来的其它操作或故障不应该对其执行结果有任何影响。

并发问题

脏读

一个事务正在对一条记录做修改,在这个事务提交之前,别的事务读取到了这个事务修改之后的数据。也就是说,一个事务读取到了其他事务还没有提交的数据,就叫做脏读。

不可重复读

在一个事务内多次读取同一数据得到的结果不一致,这可能是多次读取过程中另一个事务更新了原有的数据。即一个事务中重复读的数据不一致。针对的是数据的 update 操作。

幻读

在一个事务内多次读取到数据的总数不一致,这可能是多次读取过程中另一个事务插入或删除了一些数据。针对的是数据的 insert,delete。

更新丢失

一个事务的更新操作被另一个事务的更新操作所覆盖。

不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表。

四种隔离级别

Read Uncommitted(读取未提交)

在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。会产生脏读问题。

Read Committed(读取已提交)

这是大多数数据库系统的默认隔离级别。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。虽然不会产生脏读问题,但是会产生不可重复读的问题。

Repeatable Read(可重读)

这是 MySQL 的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据结果。解决了不可重复读的问题,但解决不了幻读的问题。

Serializable(可串行化)

这是最高的隔离级别,它强制事务串行执行。会导致更多的锁竞争,性能较差。

隔离级别一览表

事务隔离级别 脏读 不可重复读 幻读
Read Uncommitted(读取未提交)
Read Committed(读取已提交)
Repeatable Read(可重读)
Serializable(可串行化)

MySQL 设置和查看隔离级别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- 设置
mysql> set global transaction_isolation ='read-committed';
Query OK, 0 rows affected (0.00 sec)

-- 查看(全局的)
mysql> show global variables like '%isolation%';
+-----------------------+----------------+
| Variable_name | Value |
+-----------------------+----------------+
| transaction_isolation | READ-COMMITTED |
+-----------------------+----------------+
1 row in set (0.00 sec)

-- 查看(当前会话的)
mysql> select @@tx_isolation;

主流数据库的默认隔离级别

Read Committed:Oracle,SQLserver,PostgreSQL

Repeatable Read:MySQL