什么是事务
对于数据库而言,事务就是一组原子性的可执行的SQL语句,或者说是一个独立的工作单元。事务内语句,要么全部执行成功,要么全部执行失败。
事务的ACID特性
- 原子性(atomicity)
一个事务必须被视作一个不可分割的最小工作单元。整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作,这就是事务的原子性。 - 一致性(consistency)
数据库总是从一个一致性状态转换到另外一个一致性状态。 - 隔离性(isolation)
通常来说,一个事务所做的修改在最终提交以前,对其他事务不可见。 - 持久性(durability)
一旦事务提交,则其所做的修改就会永久保存到数据库中。
隔离级别
- read uncommited (读未提交)
在read uncommited级别,事务中的修改,即使没有提交,对其他事务也都是可见的。事务可以读取未提交的数据,这也被称为脏读(dirty read)。 - read commit(读已提交)
一个事务开始时,只能“看见”已经提交的事务所做的修改。 - repeatable read(可重复读)
该级别保证了在同一事务中,多次读取同样记录的结果是一致的。但是该级别的情况下,仍然会出现幻读(phantom read)的问题,所谓幻读,指的是当前某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录,当之前的事务再次读取该范围的记录时,会产生幻行(phantom row)。InnoDB通过多版本并发控制(MVCC Multiversion Concurrency Control)解决了幻读的问题。 - serializable(可串行化)
最高的隔离级别。它通过强制事务串行执行,避免了前面说的幻读的问题。
在MySQL数据库中,我们可以通过以下命令查看和修改数据库的隔离级别
show variables like '%isolation%'
该命令会显示当前数据库的隔离级别
set session|global transaction isolation level read uncommit | repeatable read | serializable | read commit
通过该命令可以修改数据库的隔离级别
MVCC(多版本并发控制)
MySQL数据库为了提高并发性能,将原本的行级锁进一步修改为MVCC的方式,避免了加锁操作。MVCC的实现,是通过保存数据在某个时间点的快照来实现的。根据事务开始的时间不同,每个事务对同一张表,同一时刻看到的数据可能是不一样的。
InnoDB的MVCC,是通过在每行记录后面保存两个隐藏的列来实现的。这两个列,一个保存了行的创建时间,一个保存行的过期时间。当然存储的并不是实际的时间值,而是系统的版本号。下面看一下在repeatable read隔离级别下,MVCC具体是如何操作的。
- select
InnoDB 会根据以下两个条件检查每行记录:
a. InnoDB只查找版本早于当前事务版本的数据行,这样保证事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改过的。
b. 行的删除版本要么未定义,要么大于当前事务版本号。这样可以确保事务读取到的行,在事务开始之前未被删除。
只有符合上述两个条件的记录,才能返回作为查询结果。 - insert
InnoDB为新插入的行保存当前系统版本号作为行版本号。 - delete
InnoDB为删除的每一行保存当前系统版本号作为行删除标识。 - update
InnoDB为插入一行新记录,保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为行删除标识。
MVCC只在read commit 和 repeatable read两个隔离级别下才工作。