5.MySQL事务
(1)事务:逻辑上的一组操作,要么都执行,要么不执行。
数据库事务:如果没有特指分布式事务,往往指的就是数据库事务。
数据事务的作用:数据库事务可以保证多个对数据库的操作(也就是 SQL 语句)构成一个逻辑上的整体。构成这个逻辑上的整体的这些数据库操作遵循:要么全部执行成功,要么全部不执行。
InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ(可重读)
MVCC 解决不可重复读问题:
虽然 RC 和 RR 都通过 MVCC 来读取快照数据,但由于 生成 Read View 时机不同,从而在 RR 级别下实现可重复读。
读已提交的隔离级别下,每次的查询都会重新创建一个新的read-view,导致每次查询的read-view都是最新的,所以再版本链的匹配中,总是能拿到其他事务已经提交的最新数据,造成了不可重复读问题的出现;
再可重复读的情况下,就只会再执行第一条查询sql的时候创建一个read-view,并且再事务结束之前都不会发生改变;这也是为什么再可重复读的隔离界别下为什么能解决不可重复读的真正原因。
MVCC➕Next-key-Lock 防止幻读:
InnoDB存储引擎在 RR 级别下通过 MVCC和 Next-key Lock 来解决幻读问题:
1、执行普通 select,此时会以MVCC快照读的方式读取数据
在快照读的情况下,RR 隔离级别只会在事务开启后的第一次查询生成 Read View ,并使用至事务提交。所以在生成 Read View 之后其它事务所做的更新、插入记录版本对当前事务并不可见,实现了可重复读和防止快照读下的 “幻读”
2、执行 select...for update/lock in share mode、insert、update、delete 等当前读
在当前读下,读取的都是最新的数据,如果其它事务有插入新的记录,并且刚好在当前事务查询范围内,就会产生幻读!InnoDB 使用 Next-key Lock
(2)并发事务带来的一致性问题:
在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务(多个用户对同一数据进行操作)。并发虽然是必须的,但可能会导致以下的问题。
·丢失修改(第一个事务内的修改结果就被丢失)
·脏读(第二个读了第一个修改的数据,但修改回滚了)
·不可重复读(第二个读了,第一个修改了,又读了,两次不同)
·幻影读(第一个读一个范围数据,第二个插入,第一个再读)
执行 delete 和 update 操作的时候,可以直接对记录加锁,保证事务安全。而执行 insert 操作的时候,由于记录锁(Record Lock)只能锁住已经存在的记录,为了避免插入新记录,需要依赖间隙锁(Gap Lock)。也就是说执行 insert 操作的时候需要依赖 Next-Key Lock(Record Lock+Gap Lock) 进行加锁来保证不出现幻读。
(3)并发事务的控制方式:锁和 MVCC:锁可以看作是悲观控制的模式,多版本并发控制(MVCC,Multiversion concurrency control)可以看作是乐观控制的模式。
锁:
·共享锁(S 锁) :又称读锁,事务在读取记录的时候获取共享锁,允许多个事务同时获取(锁兼容)。
·排他锁(X 锁) :又称写锁/独占锁,事务在修改记录的时候获取排他锁,不允许多个事务同时获取。如果一个记录已经被加了排他锁,那其他事务不能再对这条记录加任何类型的锁(锁不兼容)。
读写锁可以做到读读并行,但是无法做到写读、写写并行。
根据根据锁粒度的不同,又被分为 表级锁(table-level locking) 和 行级锁(row-level locking) 。InnoDB 不光支持表级锁,还支持行级锁,默认为行级锁。行级锁的粒度更小,仅对相关的记录上锁即可(对一行或者多行记录加锁),所以对于并发写入操作来说, InnoDB 的性能更高。不论是表级锁还是行级锁,都存在共享锁(Share Lock,S 锁)和排他锁(Exclusive Lock,X 锁)这两类。
MVCC:是多版本并发控制方法,即对一份数据会存储多个版本,通过事务的可见性来保证事务能看到自己应该看到的版本。通常会有一个全局的版本分配器来为每一行数据设置版本号,版本号是唯一的。
MVCC 在 MySQL 中实现所依赖的手段主要是: 隐藏字段、read view、undo log。
undo log : undo log 用于记录某行数据的多个版本的数据。
read view 和 隐藏字段 : 用来判断当前版本数据的可见性。
(4)SQL标准定了哪些事务隔离级别:
未提交读:允许尚未提交的数据变更
提交读:允许读取并发事务已经提交的数据 MVCC
可重复读:对同一字段多次读取结果一致 MVCC
可串行化:所有事务依次逐个执行 锁
(5)MySQL 的隔离级别是基于锁实现的吗?
MySQL 的隔离级别基于锁和 MVCC 机制共同实现的。
SERIALIZABLE (可串行化)隔离级别是通过锁来实现的,READ-COMMITTED(提交读) 和 REPEATABLE-READ(可重复读) 隔离级别是基于 MVCC 实现的。
不过,SERIALIZABLE之外的其他隔离级别可能也需要用到锁机制,就比如 REPEATABLE-READ 在当前读情况下需要使用加锁读来保证不会出现幻读。
(6)MySQL 的默认隔离级别是什么?
InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ(可重读)。我们可以通过SELECT @@tx_isolation;命令来查看,MySQL 8.0 该命令改为SELECT @@transaction_isolation;