事务的隔离级别
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 | select * from ajisun where id > 1 lock in share mode;//(共享锁) |
文件目录的访问许可权限,777每个权限数字分别代表文件所有者、群组用户、其他用户的权限。
权限 | 权限数值 | 作用 |
---|---|---|
r | 4 | read,读取。当前用户可以读取文件内容,当前用户可以浏览目录。 |
w | 2 | write,写入。当前用户可以新增或修改文件内容,当前用户可以删除、移动目录或目录内文件。 |
x | 1 | execute,执行。当前用户可以执行文件,当前用户可以进入目录。 |
组合:
1 | 7 = 4 + 2 + 1 读写运行权限 |
可重复读时用的是快照读,读的是快照数据而不是最新数据,因此会出现幻读。即提交后,发现有新增的数据(其他事务提交的),貌似之前读到的数据是“鬼影”一样的幻觉。
隔离级别为串行化时,隐式获取共享锁,用的是当前读,锁表,保证不同事务间的互斥,也就不会出现幻读了。
MVCC如何实现的:
mvcc 是多版本并发控制,通过生成记录的历史版本解决幻读问题,并提高数据库的性能,无锁实现读写并发操作。
1.mvcc 的实现主要是通过三个隐藏字段,undo log以及readView 实现的。
2.三个隐藏字段分别是隐藏主键,事务ID,回滚指针。
3.undo log是各个事务修改同一条记录的时候生成的历史记录,方便回滚,同时会生成一条版本链。
4.readView是事务在进行快照读的时候生成的记录快照,用于判断数据的可见性。
5.描述readView 可见性判断规则。