一、事务的四大特性
- 原子性(
Atomicity):事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用; - 一致性(
Consistency):执行事务前后,数据保持一致,例如转账业务中,无论事务是否成功,转账者和收款人的总额应该是不变的; - 隔离性(
Isolation):并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的; - 持久性(
Durability):一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
二、并发事务存在的问题
脏读:一个事务读取了其他事务未提交的数据
丢失修改:第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失
不可重复读:一个事务内多次读同一数据,结果不一样
幻读:一个事务内多次读同一数据,但另一个事物插入了一些数据,导致第一个事物会发现多了一些原本不存在的记录
幻读和不可重复读的区别:
-
不可重复读的重点是内容修改或者记录减少比如多次读取一条记录发现其中某些记录的值被修改;
-
幻读的重点在于记录新增比如多次执行同一条查询语句(DQL)时,发现查到的记录增加了。
三、MYSQL事务隔离级别
- READ-UNCOMMITTED(读取未提交):最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
- READ-COMMITTED(读取已提交):允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
- REPEATABLE-READ(可重复读):对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
- SERIALIZABLE(可串行化):最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。
四、MySQL并发事务的控制方式:锁 和 MVCC。
1、锁
行锁:
- 记录锁(Record Lock):也被称为记录锁,属于单个行记录上的锁。
- 间隙锁(Gap Lock):锁定一个范围,不包括记录本身。
- 临键锁(Next-Key Lock):Record Lock+Gap Lock,锁定一个范围,包含记录本身,主要目的是为了解决幻读问题(MySQL 事务部分提到过)。记录锁只能锁住已经存在的记录,为了避免插入新记录,需要依赖间隙锁
共享锁(Share Lock,S 锁)和排他锁(Exclusive Lock,X 锁):
- 共享锁(S 锁):又称读锁,事务在读取记录的时候获取共享锁,允许多个事务同时获取(锁兼容)。
- 排他锁(X 锁):又称写锁/独占锁,事务在修改记录的时候获取排他锁,不允许多个事务同时获取。如果一个记录已经被加了排他锁,那其他事务不能再对这条事务加任何类型的锁(锁不兼容)。
当前读和快照读:
快照读(一致性非锁定读)就是单纯的
SELECT 语句当前读:就是给行记录加 X 锁或 S 锁。
# 对读的记录加一个X锁 SELECT...FOR UPDATE # 对读的记录加一个S锁 SELECT...LOCK IN SHARE MODE
但是!InnoDB 实现的 REPEATABLE-READ 隔离级别其实是可以解决幻读问题发生的,主要有下面两种情况:
- 快照读:由 MVCC 机制来保证不出现幻读。
- 当前读:使用 Next-Key Lock 进行加锁来保证不出现幻读,Next-Key Lock 是行锁(Record Lock)和间隙锁(Gap Lock)的结合,行锁只能锁住已经存在的行,为了避免插入新行,需要依赖间隙锁。
MVCC 在 MySQL 中实现所依赖的手段主要是: 隐藏字段、read view、undo log。