1 引言
隔离性在实际操作中比看起来复杂很多。ANSI SQL标准定义了4种隔离级别。如果是数据库领域的新手,强烈建议在阅读特定的MySQL实现之前先熟悉ANSI SQL的通用标准。这个通用标准的目标是定义在事务内外可见和不可见的更改的规则。较低的隔离级别通常允许更高的并发性,并且开销也更低。
每种存储引擎实现的隔离级别都不尽相同。如果是其他数据库产品,可能会发现某种特性和期望的会有些不一样。可以根据所选择的存储引擎,查阅相关的手册。
2 事务隔离级别
MySQL的事务隔离级别主要有四种:READ UNCOMMITTED(未提交读)、READ COMMITTED(已提交读)、REPEATABLE READ(可重复读)、SERIALIZABLE(可串行化)
表1 ANSI SQL的隔离级别
隔离级别 | 脏读 | 不可重复度 | 幻读 | 加锁读 |
---|---|---|---|---|
READ UNCOMMITTED | 是 | 是 | 是 | 否 |
READ COMMITTED | 否 | 是 | 是 | 否 |
REPEATABLE READ | 否 | 否 | 是 | 否 |
SERIALIZABLE | 否 | 否 | 否 | 是 |
2.1 READ UNCOMMITTED(未提交读)
在READ UNCOMMITTED级别,在事务中可以查看其他事务中还没有提交的修改。这个隔离级别会导致很多问题,从性能上来说,READ UNCOMMITTED不会比其他级别好太多,却缺乏其他级别的很多好处,除非有非常必要的理由,在实际应用中一般很少使用。读取未提交的数据,也称为脏读(dirty read)。
可以读取到事务未提交的数据,隔离性差,
会出现脏读(当前内存读)、不可重复读、幻读问题。
2.2 READ COMMITTED(已提交读)
大多数数据库系统的默认隔离级别是READ COMMITTED(但MySQL不是)。READ COMMITTED满足前面提到的隔离性的简单定义:一个事务可以看到其他事务在它开始之后的修改,但在该事务提交之前,其所作的任何修改对其他事务都是不可见的。这个级别仍然允许不可重复读(nonrepeatable read),这意味着同一事务中两次执行相同语句,可能会看到不同的数据结果。
可以读取到事务已提交的数据,隔离性一般,
不会出现脏读问题,但是会出现不可重复读、幻读问题。
2.3 REPEATABLE READ(可重复读)
REPEATABLE READ解决了READ COMMITED级别的不可重复读问题,保证了在同一事务中多次读取相同行数据的结果是一样的。但是理论上,可重复读隔离级别还是无法解决另一个幻读(phantom read)的问题。所谓幻读,指的是当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录,当之前的事务再次读取该范围的记录时,会产生幻行(phantom row)。InnoDB和XtraDB存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)解决了幻读的问题。
可以防止脏读,防止不可重复读、防止幻读,但是并发能力较差;
会使用next lock锁进制,来防止幻读问题,但是引入锁机制后,锁的代价会比较高,比较耗费CPU资源,占用系统性能。
2.4 SERIALIZABLE(可串行化)
SERIALIZABLE是最高的隔离级别。该级别通过强制事务按序执行,使不同事务之间不可能产生冲突,从而解决了前面说的幻读问题。简单来说,SERIALIZABLE会在读取的每一行数据上都加锁,所以可能导致大量的超时和锁争用的问题。实际应用中很少用到这个隔离级别,除非需要严格确保数据安全且可以接受并发性能下降的结果。
隔离性比较高,可以实现串行化读取数据,但是事务的并发度就没有了;这是事务隔离的最高级别,在每条读的数据上,加上锁,使之不可能互相冲突。
3 名词解释
3.1 脏读
脏读,指的是读到了其他事务未提交的数据,未提交意味着这些数据可能保存到数据库,也可能会回滚,不保存到数据库。当这个数据发生回滚,就意味着这个数据不存在,这就是脏读。脏读最大的问题就是可能会读到不存在的数据。
当数据库的事务隔离级别为读未提交,就会发生脏读现象。
3.2 不可重复读
不可重复读,指的是在一个事务内,最开始读到的数据和事务结束前的任意时刻读到的同一批数据出现不一致的情况。
当数据库的事务隔离级别为读未提交、读提交时,就会发生不可重复读现象。
3.3 幻读
幻读,例如事务 A 对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。此时,突然事务 B 插入了一条数据并提交了,当事务 A 提交了修改数据操作之后,再次读取全部数据,结果发现还有一条数据未更新,给人感觉好像产生了幻觉一样。这就是幻读!
当数据库的事务隔离级别为读未提交、读提交、可重复读时,就会发生幻读现象。
4 示例
如:设置全局事务隔离级别
# 全局设置为未提交读
set global transaction_isolation='READ-UNCOMMITTED';
# 全局设置为已提交读
set global transaction_isolation='READ-COMMITTED';
# 全局设置为可重复读
set global transaction_isolation='REPEATABLE-READ';
# 全局设置为串行化
set global transaction_isolation='SERIALIZABLE';
查看事务隔离级别状态:
show variables like 'transaction_isolation';
返回面试宝典