数据库的隔离级别

常用数据库的默认隔离级别

MySQL的默认隔离级别是Repeatable
Oracle的默认隔离级别是Read committed

事务的隔离级别

1、未提交读(Read uncommitted)
2、提交读(Read committed)
3、可重复读(Repeatable reads)
4、可序列化(Serializable)

读未提交(Read uncommitted)会导致脏读

1、加锁情况

事务在读数据的时候并未对数据加锁
事务在修改数据的时候只对数据增加行级共享锁

2、举例

A事务执行SELECT age FROM users WHERE id = 1; 查到结果为20
B事务执行UPDATE users SET age = 21 WHERE id = 1; 但并未提交
此时A事务再次执行SELECT age FROM users WHERE id = 1; 查到结果为21

3、总结

一个事务读到另一个事务未提交的数据为脏读

读已提交(Read committed)

1、加锁情况

事务对当前被读取的数据加 行级共享锁(当读到时才加锁),一旦读完该行,立即释放该行级共享锁
事务在更新某数据的瞬间(就是发生更新的瞬间),必须先对其加 行级排他锁,直到事务结束才释放

2、举例

A事务执行SELECT * FROM users WHERE id = 1; 查到结果为20
B事务执行UPDATE users SET age = 21 WHERE id = 1;
A事务执行SELECT * FROM users WHERE id = 1; 查到结果为20
B事务 commit;
A事务执行SELECT * FROM users WHERE id = 1; 查到结果为21
最后一次读取的结果已经变了

3、总结

一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。
这种隔离级别保证了读到的任何数据都是提交的数据,避免了脏读(dirty reads)。

可重复读(Repeatable reads)

1、加锁情况

事务在读取某数据的瞬间(就是开始读取的瞬间),必须先对其加 行级共享锁,直到事务结束才释放;
事务在更新某数据的瞬间(就是发生更新的瞬间),必须先对其加 行级排他锁,直到事务结束才释放。

2、可重复读举例

A事务执行SELECT * FROM users WHERE id = 1;
B事务执行UPDATE users SET age = 21 WHERE id = 1;,此时处于阻塞状态,无法执行,需等待A事务执行完毕
A事务commit
B事务继续执行

3、幻读举例

A事务执行SELECT * FROM users WHERE age BETWEEN 10 AND 30; 此时查到两条数据
B事务执行INSERT INTO users(age) VALUES (3); commit;
A事务再次执行SELECT * FROM users WHERE age BETWEEN 10 AND 30; 此时查到了三条数据

4、总结

A事务执行期间,所做的查询和修改都会加锁,其他事务只能查询不能修改,若要修改,只能等待A事务执行完成
解决了不可重复读,但是解决不了幻读

可序列化(Serializable)

1、加锁情况

事务在读取数据时,必须先对其加 表级共享锁 ,直到事务结束才释放;
事务在更新数据时,必须先对其加 表级排他锁 ,直到事务结束才释放。

2、举例

事务1正在读取A表中的记录时,则事务2也能读取A表,但不能对A表做更新、新增、删除,直到事务1结束
事务1正在更新A表中的记录时,则事务2不能读取A表的任意记录,更不可能对A表做更新、新增、删除,直到事务1结束

3、总结

可序列化可以解决幻读,但是同时会带来其他问题
(1)无法读取其它事务已修改但未提交的记录。(脏读)
(2)在当前事务完成之前,其它事务不能修改目前事务已读取的记录。(可重复读)
(3)在当前事务完成之前,其它事务所插入的新记录,其索引键值不能在当前事务的任何语句所读取的索引键范围中。(幻读)

原文地址:https://www.cnblogs.com/jis121/p/11054246.html