1.隔离级别
数据库的隔离级别有以下四种:
- 读未提交
- 读已提交
- 可重复读
- 串行化
2.数据库读取中的问题
隔离级别主要用来解决以下三个问题:
- 脏读
- 不可重复读
- 幻读
2.1.最简单情况
最简单的情况就是读未提交,其本质是:
事务在修改数据的时候只对数据增加行级共享锁。
事务在读数据的时候并未对数据加锁。
读未提交会引起脏读的问题。
2.2.脏读
假设 A 给 B 打 5000 块钱,修改了数据库当时还没有提交。此时 B 读取数据库中的自己账户的余额,以为自己收到了 5000 块钱。然而之后 A 并没有提交,而是回滚了该数据,所以最终 B 的账余额并没有增加。所以 B 读取到的是错误的信息,这就是脏读。
为了避免这种情况,需要把数据库的隔离级别设置为读已提交。其本质是:
事务对当前被读取的数据加 行级共享锁(当读到时才加锁),一旦读完该行,立即释放该行级共享锁。
事务在更新某数据的瞬间(就是发生更新的瞬间),必须先对其加 行级排他锁,直到事务结束才释放。
2.3.不可重复读
假设一个账户中有 5000 块钱, A 和 B 同时从这个账户中取钱,当 A 查看余额时发现账户中有 5000 块钱,之后 B 取走了这 5000 块钱,当 A 再取钱的时候发现钱已经被取走了。也就是说,在同一事务中,A 对自己的账户进行的两次查询得到了不同的结果,这就是不可重复读。
为了避免这种情况,需要把数据库的隔离级别设置为可重复读。其本质是:
事务在读取某数据的瞬间(就是开始读取的瞬间),必须先对其加 行级共享锁,直到事务结束才释放。
事务在更新某数据的瞬间(就是发生更新的瞬间),必须先对其加 行级排他锁,直到事务结束才释放。
不可重复读与脏读的区别在于,脏读读出的数据是无效的未提交的信息(脏读也称为无效数据读出)。而不可重复读两次读取的信息都是有效的已提交的信息,只不过在这两次读取期间数据被提交了而已。
可重复读和读已提交最大的区别就在于事务在读的过程中行级共享锁的寿命。读已提交是读取完就释放,而可重复读是事务结束才释放,
2.4.幻读
假设 A 正在查询自己银行卡中的本月的消费记录,恰好此时 B 拿着 A 的信用卡刷了一笔钱。也就是说,在同一事务中,A 读到的两次消费记录不一致。新的结果中出现了幻影行,这就是幻读。
为了避免这种情况,需要把数据库的隔离级别设置为串行化。其本质是:
事务在读取数据时,必须先对其加 表级共享锁 ,直到事务结束才释放;
事务在更新数据时,必须先对其加 表级排他锁 ,直到事务结束才释放。
幻读与不可重复读的区别在于,不可重复读可以通过对读取到的数据加锁来避免。然而,你不可能给一条还未插入到数据库中的数据进行加锁,因此幻读是无法通过这种机制来避免,所以才要锁全表。
3.数据库的默认隔离级别
MySQL 的默认隔离级别是可重复读.
大多数数据库如 Sql Server , Oracle 的默认级别是读已提交。