献上一张图
事务的特性
事务的四个特性,ACID。原子性:atomicity,一致性:consistent,隔离性:isolate,持久性durability。
原子性:事务的操作必须是全部都完成,或者全部都失败,不会出现成功一部分,另一部分失败的情况。
一致性:事务前后,数据满足完整性约束,数据库保持一致的状态。
隔离性:数据库可以多个事务并发执行,不会互相干扰。
持久性给:事务完成后,对数据的修改是持久的,系统故障也不会消失。
InnoDB通过什么技术保证事务的四个特性?
持久性是通过redo log,重做日志保证的。 原子性是通过undo log,回滚日志保证的。 隔离性是通过MVCC(多版本并发控制)或者锁机制保证的。 一致性是前面三个特性保证。
并行事务存在什么问题?
同时处理多个事务的时候,可能会出现脏读、幻读、不可重复读的问题。
脏读
一个事务读取到了其他未提交事务修改过的数据,就称为产生了脏读。
不可重复读
一个事务前后读取一个数据,但是不一致,说明发生了不可重复读。
幻读
一个事务内多次查询某个数据的数量,如果前后两次数量不一样,说明发生了幻读。
SQL标准有四种隔离级别来规避这个现象。
如下:读未提交、读提交、可重复读、串行化。隔离级别越高,性能效率越低。
不同的隔离级别下,可能会发生的异常也不同。
MySQL的可重复读隔离级别可以很大程度避免幻读。
针对快照读,就是普通的select语句,MySQL通过MVCC方式解决幻读。可重复读隔离级别下,事务执行过程中看到的数据跟事务开始时的数据是保持一致的,不会受到其他事务的影响。
针对当前读,(如select ... for update等语句),是通过 next-key lock
(记录锁+间歇锁)方式解决的幻读,因为执行当前读语句的时候,会加上临键锁,这样其他事务在锁范围内尝试插入记录的时候,这条插入语句就会被阻塞。
四种隔离级别是如何实现的呢?
读未提交和串行化都好理解,前者是直接读取最新数据即可,后者就阻塞呗。
重点是读已提交和可重复读。
它们是通过 Read View
实现的,但是区别在于Read View 的创建时机不同,它相当于一个数据快照。
读已提交是在每个语句执行之前重新生成Read View,也就是读视图,而可重复读是启动事务时创建Read View,整个事务期间使用这个读视图。
执行开始事务命令,不意味着启动事务
MySQL有两种开启事务的命令,分别是begin/start transaction 命令、 start transaction with consistent snapshot. 前者执行完毕后,开始执行第一条sql语句时才开始事务,后者立即开始事务。