事务的隔离级别

事务的隔离级别

MySQL事务主要 用于处理操作量大,复杂度高的数据。并发事务会导致数据脏读、不可重复读、幻读、更新丢失。

事务有四种隔离级别:未提交读、提交读、可重复读、串行化,隔离级别越高的数据库越安全,能解决的并发一致性问题也就越多。

第一种隔离级别会造成脏读、不可重复读和幻读;

第二种隔离级别容易造成不可重复读、幻读;

第三种隔离级别会造成幻读;

第四种隔离级别会强制的将并行操作改为串行,可避免幻读的出现;

隔离级别越高,就代表着越安全,但是同时性能效率也就越低。

InnoDB引擎通过MVCC,解决了脏读、不可重复读,通过MVCC + Next-Key Lock(临键锁)来解决幻读,实现了事务的隔离级别Repeatable Read(可重复读)。

可重复读隔离级别下,并发问题需要靠开发者显式或隐式使用锁来自行解决。

MVCC

MySql默认的是可重复读。

MySql采用了MVCC和间隙锁来防止幻读的出现。

MVCC通过添加两个隐式的列,在很多情况下都避免了加锁操作,如果需要加锁,也只锁定了必要的行。

MVCC(Multiversion Concurrency Control)多版本并发控制。即通过数据行的多个版本管理来实现数据库的并发控制,使得在InnoDB事务隔离级别下执行一致性读操作有了保障。

  • InnoDB实现MVCC,主要是为了提高数据库的并发性能,在无锁的情况下也能处理读写并发(并发读,这个读指的是快照读而不是当前读)。
  • MySQl中只有InnoDB支持MVCC,其他存储引擎不支持。

在InnoDB中,会对增删改操作自动添加排它锁,因此两个事务不会出现脏写的情况,也就是不会出现两个事务交叉着对同一条记录进行修改,必须等待第一个事务提交才能进行第二个事务。

快照读与当前读:

快照读

顾名思义读取的是一份快照数据,所以读到的并不一定是最新数据,可能是历史数据。

其次简单的select查询就是快照读,不加锁非阻塞读,降低数据库的开销。

最后,快照读在隔离级别是串行化级别是没有意义的,因为串行化的sql都是排队执行的,不存在并发,所以就会变成当前读。

当前读

当前读获取的数据是最新数据,而且在读取时不能被其他修改,所以会对读取的记录加锁来控制。

加锁的SELECT(共享或排它锁)或对数据进行增删改操作(自动添加排它锁)都会进行当前读。读权限是最基本的,如果想写入,则必须先打开文件读取。

1
2
3
select * from ajisun where id > 1 lock in share mode;//(共享锁)
// 或
select * from ajisun where id >1 for update;//(排它锁)

文件目录的访问许可权限,777每个权限数字分别代表文件所有者、群组用户、其他用户的权限。

权限 权限数值 作用
r 4 read,读取。当前用户可以读取文件内容,当前用户可以浏览目录。
w 2 write,写入。当前用户可以新增或修改文件内容,当前用户可以删除、移动目录或目录内文件。
x 1 execute,执行。当前用户可以执行文件,当前用户可以进入目录。

组合:

1
2
3
4
7 = 4 + 2 + 1    读写运行权限
5 = 4 + 1 读和运行权限

4 = 4 只读权限

可重复读时用的是快照读,读的是快照数据而不是最新数据,因此会出现幻读。即提交后,发现有新增的数据(其他事务提交的),貌似之前读到的数据是“鬼影”一样的幻觉。

隔离级别为串行化时,隐式获取共享锁,用的是当前读,锁表,保证不同事务间的互斥,也就不会出现幻读了。

MVCC如何实现的:

mvcc 是多版本并发控制,通过生成记录的历史版本解决幻读问题,并提高数据库的性能,无锁实现读写并发操作。

1.mvcc 的实现主要是通过三个隐藏字段,undo log以及readView 实现的。

2.三个隐藏字段分别是隐藏主键,事务ID,回滚指针。

3.undo log是各个事务修改同一条记录的时候生成的历史记录,方便回滚,同时会生成一条版本链。

4.readView是事务在进行快照读的时候生成的记录快照,用于判断数据的可见性。

5.描述readView 可见性判断规则。