数据库事务——事务隔离级别
文章目录
数据库的事务隔离级别
SQL 标准定义了四种隔离级别,这四种隔离级别分别是:
- 读未提交(READ UNCOMMITTED);
- 读提交 (READ COMMITTED);
- 可重复读 (REPEATABLE READ);
- 串行化 (SERIALIZABLE)
事务隔离是为了解决脏读、不可重复读、幻读问题,下表展示了 4 种隔离级别对这三个问题的解决程度:
隔离级别 | 脏读 | 不可重复读 | 幻读 |
READ UNCOMMITTED | 可能 | 可能 | 可能 |
READ COMMITTED | 不可能 | 可能 | 可能 |
REPEATABLE READ | 不可能 | 不可能 | 可能 |
SERIALIZABLE | 不可能 | 不可能 | 不可能 |
上述4种隔离级别MySQL都支持,并且InnoDB存储引擎默认的支持隔离级别是可重复读(REPEATABLE READ),但是与标准SQL不同的是,InnoDB存储引擎在REPEATABLE READ事务隔离级别下,使用Next-Key Lock的锁算法,因此避免了幻读的产生。所以,InnoDB存储引擎在默认的事务隔离级别下已经能完全保证事务的隔离性要求,即达到SQL标准的SERIALIZABLE隔离级别。
并发情况下,读操作可能存在的三类问题:
- 脏读:当前事务(A)中可以读到其他事务(B)未提交的数据(脏数据),这种现象是脏读。
- 不可重复读:在事务A中先后两次读取同一个数据,两次读取的结果不一样,这种现象称为不可重复读。
脏读与不可重复读的区别在于:前者读到的是其他事务未提交的数据,后者读到的是其他事务已提交的数据。
- 幻读:在事务A中按照某个条件先后两次查询数据库,两次查询结果的条数不同,这种现象称为幻读。
不可重复读与幻读的区别可以通俗的理解为:前者是数据变了,后者是数据的行数变了。
MySQL的事务隔离级别的实现
InnoDB支持四种隔离级别,每种级别解决掉的问题如下表:
脏读 | 不可重复读幻读 | 幻读 | |
READ UNCOMMITTED | Y | Y | Y |
READ COMMITTED | N | Y | Y |
REPEATABLE READ(默认) | N | N | N |
SERIALIZABLE | N | N | N |
这四种隔离级别的实现机制如下:
1. READ UNCOMMITTED & READ COMMITTED:
通过Record Lock算法实现了行锁,但READ UNCOMMITTED允许读取未提交数据,所以存在脏读问题。
而READ COMMITTED允许读取提交数据,所以不存在脏读问题,但存在不可重复读问题。
2. REPEATABLE READ:
使用Next-Key Lock算法实现了行锁,并且不允许读取已提交的数据,所以解决了不可重复读的问题。另外,该算法包含了间隙锁,会锁定一个范围,因此也解决了幻读的问题。
3. SERIALIZABLE:
对每个SELECT语句后自动加上LOCK IN SHARE MODE,即为每个读取操作加一个共享锁。因此在这个事务隔离级别下,读占用了锁,对一致性的非锁定读不再予以支持。
MySQL事务小细节
事务可以嵌套吗?
可以,因为嵌套事务也是众多事务分类中的一种,它是一个层次结构框架。有一个顶层事务控制着各个层次的事务,顶层事务之下嵌套的事务被称为子事务,它控制每一个局部的变换。
需要注意的是,MySQL数据库不支持嵌套事务。
如何实现可重复读?如何解决幻读问题?
MySQL的InnoDB引擎,在默认的REPEATABLE READ的隔离级别下,实现了可重复读,同时也解决了幻读问题。它使用Next-Key Lock算法实现了行锁,并且不允许读取已提交的数据,所以解决了不可重复读的问题。另外,该算法包含了间隙锁,会锁定一个范围,因此也解决了幻读的问题。
MySQL事务的回滚
在MySQL默认的配置下,事务都是自动提交和回滚的。当显示地开启一个事务时,可以使用ROLLBACK语句进行回滚。
该语句有两种用法:
ROLLBACK
:要使用这个语句的最简形式,只需发出ROLLBACK。同样地,也可以写为ROLLBACK WORK,但是二者几乎是等价的。回滚会结束用户的事务,并撤销正在进行的所有未提交的修改。ROLLBACK TO [SAVEPOINT] identifier
:这个语句与SAVEPOINT命令一起使用。可以把事务回滚到标记点,而不回滚在此标记点之前的任何工作