MySQL数据库隔离级别详解
- 数据库事务的概念和特性(ACID)
- 数据库事务可能出现的问题(脏读、不可重复读、幻读)
- 数据库事务的四种隔离级别(未提交读、已提交读、可重复读、串行化)
- MySQL的默认隔离级别(可重复读)和如何修改隔离级别
- MySQL对不同隔离级别实现原理:锁机制和MVCC机制
什么是数据库事务?
数据库事务(Transaction)是指一个或多个SQL语句组成的一个执行单元,它具有以下四个特性,通常称为ACID原则:
- 原子性(Atomicity):事务中的所有操作要么全部成功,要么全部失败,不会出现部分完成的情况。
- 一致性(Consistency):事务执行前后,数据保持逻辑上的一致性,不会出现破坏数据完整性和业务规则的情况。
- 隔离性(Isolation):多个事务并发执行时,互相不干扰,每个事务都感觉自己是独占地访问数据。
- 持久性(Durability):事务一旦提交,对数据的修改就会永久保存在数据库中,即使发生系统故障也不会丢失。
数据库事务可能出现哪些问题?
在实际应用中,为了提高系统的并发能力和响应速度,通常会允许多个事务同时执行。但是这样就可能导致一些数据不一致的问题。常见的有以下三种:
- 脏读(Dirty Read):一个事务读取了另一个未提交的事务修改过的数据。如果后者回滚,则前者读取到的数据就是无效的。
- 不可重复读(Non-repeatable Read):一个事务在两次查询之间,数据被另一个已提交的事务修改过。导致两次查询结果不一致。
- 幻读(Phantom Read):一个事务在两次查询之间,数据被另一个已提交的事务插入或删除。导致两次查询结果数量不一致。
数据库有哪些隔离级别?
为了解决上述问题,在SQL标准中定义了四种隔离级别来控制并发访问时可能出现的问题。它们分别是:
- 未提交读(Read Uncommitted):最低级别,允许脏读、不可重复读和幻读。
- 已提交读(Read Committed):只允许不可重复读和幻读。
- 可重复读(Repeatable Read):只允许幻读。
- 串行化(Serializable):最高级别,完全避免所有问题。
隔离级别越高,并发能力越低;反之亦然。
MySQL默认使用哪种隔离级别?如何修改?
MySQL默认使用可重复读作为隔离级别,这是因为它能够保证数据的一致性和完整性,同时也能提供较高的并发能力。
如果想要修改隔离级别,可以使用以下语句:
- 查看当前隔离级别:
SELECT @@tx_isolation;
- 修改当前会话的隔离级别:
SET SESSION transaction isolation level level;
- 修改全局的隔离级别:
SET GLOBAL transaction isolation level level;
其中,level可以是以下值之一:
- read uncommitted
- read committed
- repeatable read
- serializable
需要注意的是,修改隔离级别会影响事务的执行效果和性能,所以要根据实际情况选择合适的隔离级别。
MySQL如何实现不同的隔离级别?
MySQL主要使用两种机制来实现不同的隔离级别,分别是锁机制和MVCC机制。
锁机制
锁机制是指在访问数据时加上一定的约束,防止其他事务对数据进行修改或删除。根据锁定范围和方式,MySQL有以下几种锁类型:
- 表锁(Table Lock):最简单的锁类型,对整张表加锁。分为读锁(共享锁)和写锁(排他锁)。读锁允许多个事务同时读取同一张表;写锁只允许一个事务对表进行写操作,并阻塞其他事务对该表的所有操作。
- 行锁(Row Lock):最灵活的锁类型,对单行数据加锁。分为共享行锁(S Lock)和排他行锁(X Lock)。共享行锁允许多个事务同时读取同一行数据;排他行锁允许一个事务对一行数据进行写操作,并阻塞其他事务对该行的所有操作。
- 间隙锁(Gap Lock):针对索引记录之间的间隙加锁,防止其他事务在该范围内插入数据。只在可重复读和串行化隔离级别下生效。
- 临键锁(Next-Key Lock):结合了行锁和间隙锁,对索引记录及其前后的间隙加锁。可以避免幻读的问题。
MySQL中,表锁是由MyISAM引擎实现的;行锁、间隙锁和临键锁是由InnoDB引擎实现的。
MVCC机制
MVCC(Multi-Version Concurrency Control)是一种多版本并发控制机制,它通过为每行数据保存多个版本(快照),来实现非阻塞地读取数据,提高并发性能。每个版本都有一个事务版本号,表示该版本是由哪个事务创建的。
当一个事务开始时,会获取一个当前系统版本号(也称为视图),表示该事务启动时刻的数据库状态。当一个事务要读取一行数据时,会根据以下规则来判断该行数据是否可见:
- 如果该行数据的创建版本号大于当前事务的系统版本号,说明该行数据是在当前事务启动后才创建的,因此不可见。
- 如果该行数据有删除版本号,并且小于或等于当前事务的系统版本号,说明该行数据已经被删除,并且删除操作发生在当前事务启动前或期间,因此不可见。
- 其他情况下,该行数据可见。
MVCC只在已提交读和可重复读两种隔离级别下工作,在未提交读下无效,在串行化下相当于加了全局锁。