MySQL的事务的四大特性和隔离级别
定义
MySQL的事务的四大特性和隔离级别,事务就是一组原子性的SQL语句,或者说一个独立的工作单元。事务内的SQL语句,要么全部执行成功,要么全部执行失败。
1. 事务的四大特性(ACID)
- 原子性(atomicity):一个事务必须视为一个不可分割的最小单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行成功其中的一部分操作,这就是事务的原子性。
- 一致性(consistency):数据总是从一个一致性的状态转换到另一个一致性的状态。
- 隔离性(isolation):一个事务所做的修改在最终提交以前,对其他事务是不可见的,多个并发事务之间是相互隔离的。关于事务的隔离性,MySQL提供了四种隔离级别。
- 持久性(durability):一旦事务提交,所做的修改会永久保存到数据库中。即使系统崩溃,修改的数据也不会丢失。
脏读,不可重复读,可重复读,串行化(读)
2.1 脏读
脏读是指在一个事务处理过程中读取了另一个未提交的事务中的数据。
2.2 不可重复读
不可重复读是指对于数据库中的某个数据,一个事务内多次查询却返回了不同的数据值,这是由于在事务执行过程中,数据被另一个事务修改并提交了。
2.3 可重复读:
可避免脏读、不可重复读的发生。
2.4 串行化(读)
可避免脏读、不可重复读、幻读的发生。
隔离级别
关于事务的隔离性,MySQL提供了四种隔离级别:
- Serializable(串行化):可避免脏读、不可重复读、幻读的发生。(级别最高)
- Repeatable-read(可重复读):可避免脏读、不可重复读的发生。
- Read-committed(读已提交):可避免脏读的发生。
- Read-uncommitted(读未提交):最低级别,任何情况都无法保证。(级别最低)
以上四种隔离级别最高的是Serializable,最低的是Read uncommitted级别。当然,隔离级别越高,执行效率就越低。
MySQL数据库中默认的隔离级别为Repeatable read。
像Serializable这样的级别,就是以锁表的方式(类似于Java多线程中的锁)使得其他的线程只能在锁外等待,选用哪一种隔离级别应该根据实际情况而定。
幻读(phantom read)
前提条件:InnoDB引擎,可重复读隔离级别,使用当前读时。
表现:一个事务(同一个read view)在前后两次查询同一范围的时候,后一次查询看到了前一次查询没有看到的行。两点需要说明:
1、在可重复读隔离级别下,普通查询是快照读,是不会看到别的事务插入的数据的,幻读只在当前读下才会出现。
2、幻读专指新插入的行,读到原本存在行的更新结果不算。因为当前读的作用就是能读到所有已经提交记录的最新值。
幻读的影响
- 会造成一个事务中先产生的锁,无法锁住后加入的满足条件的行。
- 产生数据一致性问题,在一个事务中,先对符合条件的目标行做变更,而在事务提交前有新的符合目标条件的行加入。这样通过binlog恢复的数据是会将所有符合条件的目标行都进行变更的。
幻读产生的原因
行锁只能锁住行,即使把所有的行记录都上锁,也阻止不了新插入的记录。
举例
第一步建表并插入5条记录:1,2,3,4,5
事务1(开启事务查询发现没有记录6准备插入):
事务2(开启事务,发现没有记录6,将6插入,并提交事务):
事务1:查询发现没有记录6,现在开始进行插入6:
没有的记录我要插入却告诉已经存在,这就是通常说的幻读。
如何解决幻读
- 将两行记录间的空隙加上锁,阻止新记录的插入;这个锁称为间隙锁
- 间隙锁与间隙锁之间没有冲突关系。跟间隙锁存在冲突关系的,是往这个间隙中插入一个记录这个操作。
Serializable 可串行化
这是最高的隔离级别
它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简而言之,它是在每个读的数据行上加上共享锁。
在这个级别,可能导致大量的超时现象和锁竞争
在该隔离级别下,可以解决前面出现的脏读、不可重复读和幻读问题,但也会导致大量的超时和锁竞争现象,一般不推荐使用。