事务的四大特性 - ACID
- 原子性 - Atomicity
- 一个事务是一个不可分割的工作单位,事务中的所有操作要么都完成,要么全都不做;如果事务中的一个sql语句执行失败,所有已执行的语句必须回滚,数据库退回到事务发生之前的状态。
- 实现原理:undo log - 回滚日志
当事务对数据库进行修改时,InnoDB会生成对应的undo log;如果事务执行失败或调用了rollback,则InnoDB会根据undo log的内容做与之前相反的工作。
- 持久性 - Durability
- 事务一旦提交,对于数据库的改变应该是永久性的,接下来的其他操作或故障不应该对其有任何影响。
- 实现原理:redo log - 重做日志
向数据库写入数据时,会首先写入缓存Buffer Pool,Buffer Pool中修改的数据会定期刷新到磁盘中(刷脏),若MySQL宕机,缓存中的数据未来得及刷新到磁盘,数据就会丢失,导致持久性无法保证。
引入redo log,当数据修改时,先在redo log中记录这次操作,再修改Buffer Pool中的数据。事务提交时,redo log会保存到磁盘,若MySQL宕机,则重启时可以读取redo log中的数据对数据库进行恢复。
刷脏是以页为单位写入磁盘的,因此一个小修改也要整页写入,而redo log只包含真正需要写入的部分,无效IO大大减少。
- 隔离性 - Isolation
- 事务内部操作与其它事务是隔离的,隔离性追求的是并发情形下事务之间互不干扰。
- 锁机制 隔离性要求同一时刻只能有一个事务对数据进行写操作,事务在修改数据前需要获得相应的锁,并且只有当事务提交后,锁才会释放。MyIsam只支持表锁,InnoDB同时支持表锁和行锁,一般情况使用行锁。
- 并发情况下读操作可能出现三种问题:
- 脏读
当前事务可以读到其它事务未提交的数据(脏数据)
- 不可重复读
在一个事务中先后两次读取同一个数据,读取结果不同,即读到其它事务修改并提交的数据。
- 幻读
在一个事务中先后两次查询数据库,两次查询到的条数不同,即读取到其它事务插入/删除并提交的数据。
- 事务隔离级别
- MySQL默认隔离级别是可重复读,InnoDB下不会出现幻读(MVCC)。
- 一致性 - Consistency
- 指事务结束后,数据库的完整性约束没有被破坏,事务执行前后都是合法的数据状态。
- 实现一致性的措施包括:
- 保证原子性、持久性和隔离性。
- 数据库本身对数据更改进行限制。
- 应用层面进行保障。
MVCC - 多版本并发控制
- 全称 Multi-Version Concurrency Control,使得MySQL在RR的隔离级别下解决脏读、不可重复读、幻读的问题。
- 实现机制:创建一致性视图
- 事务创建一致性视图时,会读取到已分配的事务的版本,记录最早事务的版本和最晚事务的版本。
- 若数据修改的版本早于最早事务的版本,则数据可读;
- 若数据修改的版本晚于最晚事务的版本,则数据不可读;
- 若数据修改的版本处于最早和最晚之间:则该数据版本对应的事务若已提交,则可读,否则不可读。
- 事务仅在第一次使用select语句进行读操作时创建一致性视图,假设有A事务早于B事务开始,但B事务修改数据并提交后A事务才第一次使用select语句读取数据,则会读取到B事务修改的数据。
- MVCC仅针对读操作(SELECT),写操作不创建一致性视图(UPDATE, INSERT, DELETE)。