1 MySQL的事物隔离级别是为了解决什么问题?
事物隔离级别是为了解决事物并发问题。
事物并发问题其实就和我们在编写并发程序时的线程安全问题是类似的,线程安全问题是多个线程同时修改了一个变量,如果不加锁,就可能出现类似于超卖这种类型的问题。事物并发,是多个客户端连接同时修改数据库的某条记录也可能会出现类似的问题,并且事物是会发生回滚的,这就又加重了问题的复杂程度。
我们将事物并发问题总结起来,就是以下几种:
- 脏读: 事务A读取了事务B修改的数据,然后事物B回滚,那么事物A读取到的数据是脏数据
- 不可重复读: 事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取到的同一数据时不一致。
- 幻读: 事物A将数据库中所有数据修改为另一种形式,但是事物B就在这个时候插入了一条新的数据,事物A修改结束后发现仍有一条记录没有修改过来,就像发生了幻觉一样,这就叫幻读。
总结:
不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。
解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁整张表。
2 MySQL中都有哪些隔离级别?
SQL的标准就是定义了四种隔离级别,
基于上诉事物并发问题,MySQL为我们提供了几种解决方案,就是如下几种(√ 选的是会出现问题的)
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(read-uncommitted) | √ | √ | √ |
读已提交(read-committed) | √ | √ | |
可重复读(repeatable-read)默认 | (√) | ||
串行化(serializable) |
每一种隔离级别其实也就是锁的级别,什么问题都忽略即不加锁,什么问题都解决即将并行执行转为串行执行。
随着加锁的程度越来越强,数据库的并发性能越来越弱。
3 MySQL的每种隔离级别都会加什么锁?
读未提交(性能优,问题多)
加锁情况:
- 事务在读数据的时候并未对数据加锁。
- 事务在修改数据的时候只对数据增加行级共享锁。
读已提交(互联网常常使用的隔离级别,性能优)
读已提交其实是针对于事物而言,不读取没有提交的事物,这样就不会产生脏读。
读已提交的事务隔离级别是大多数流行数据库的默认事务隔离界别,比如 Oracle,但是不是 MySQL 的默认隔离界别。
加锁情况:只会对索引增加 Record Lock
- 事务对当前被读取的数据加行级共享锁(当读到时才加锁),一旦读完该行,立即释放该行级共享锁;
- 事务在更新数据的瞬间(就是发生更新的瞬间),必须先对其加行级排他锁,直到事务结束才释放。
可重复读
可重复读是将读取到的数据锁定起来,保证在事物内,读取到的数据是一致的。
MySQL为了解决幻读问题增加了 Gap Lock 和 Next-Key Lock(可通过配置文件设置);
加锁情况:为了解决幻读的问题,在支持 Record Lock 的同时,还支持 Gap Lock 和 Next-Key Lock;
- 事务在读取某数据的瞬间(就是开始读取的瞬间),加行级共享锁,直到事务结束才释放;
- 事务在更新某数据的瞬间(就是发生更新的瞬间),加行级排他锁,直到事务结束才释放。
串行化
直接把并行变为串行,相当于单线程执行任务,性能极低,一般不会使用。
加锁情况:
- 事务在读取数据时,必须先对其加表级共享锁 ,直到事务结束才释放;
- 事务在更新数据时,必须先对其加表级排他锁 ,直到事务结束才释放。
推荐两篇之前写的博文:
如果对MySQL锁概念不了解的可以阅读《MYSQL的锁介绍》。
MySQL为了优化加锁的性能,采用了MVCC多版本并发控制,如果不了解可以阅读《MySQL中的MVCC是怎么实现的,你们知道吗?》。
4 总结
事物的隔离级别就是数据库为我们提供了选择的权利,在性能和数据准确程度上,根据业务做取舍,有舍必有得。
对于MySQL来说InnonDB引擎才会有事物和事物隔离级别的说法。