四种隔离级别
我们愿意舍弃一部分隔离性来换取一部分性能在这里就体现在:设立一些隔离级别隔离级别越低并发问题发生的就越多。
SQL标准 中设立了4个 隔离级别 :
READ UNCOMMITTED :读未提交,在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。不能避免脏读、不可重复读、幻读。
READ COMMITTED :读已提交,它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。可以避免脏读,但不可重复读、幻读问题仍然存在。
REPEATABLE READ :可重复读,事务A在读到一条数据之后,此时事务B对该数据进行了修改并提交,那么事务A再读该数据,读到的还是原来的内容。可以避免脏读、不可重复读,但幻读问题仍然存在。这是MySQL的默认隔离级别。
SERIALIZABLE :可串行化,确保事务可以从一个表中读取相同的行。在这个事务持续期间,禁止其他事务对该表执行插入、更新和删除操作。所有的并发问题都可以避免,但性能十分低下。能避免脏读、不可重复读和幻读。
不可重复读问题
在读已提交的事务隔离级别并没有解决不可重复读的问题
测试
#设置事务隔离级别 设置为读已提交
SET SESSION transaction_isolation ='READ-COMMITTED'
#查看事务隔离级别
SHOW VARIABLES LIKE 'transaction_isolation'
#在事务A中
begin
#此时查询到的数据是 测试
select * from student where id=1
#在事务B中
begin
update student set name='测试11' where id=1
commit
#此时在事务A中读取到的数据是
测试11
这时就发生了不可重复读的问题
#如果把事务隔离级别设置为 可重复读 就解决了可重复读的问题
SET SESSION transaction_isolation ='REPEATABLE-READ'
问题是既然MySQL有事物隔离性,那为什么还会产生脏读?
这个事情不能简单的一概而论,还得结合锁和MVCC相关的知识来分析
一个select操作
如果不加锁(普通的select等),称为快照读,读取的是MVCC版本链里的快照版本(至于读哪一版本的数据,就得看隔离级别了)
如果加了锁(如select for update等),称为当前读,读取的是最新版本(也就是别的事务提交的版本)
所以这样就很清晰了:
在事务隔离级别为读未提交的情况下,事务B读取到的可能是事务A未提交的存在于版本链里的数据,这样就是脏读了。
有人可能是数据不是加锁了吗,为啥还能读?
我读取的是版本链里的数据,你加锁是加在最新落库的数据表里的表记录,跟我有什么关系?
所以最终结果就很清楚了,并不是一级封锁协议不能避免度脏数据,想下面这两周情况就不会发生脏读:
1)在非读未提交(读已提交、可重复读、串行化)隔离别下,不会出现脏读
2)在select加锁的情况下,不管什么级别,也不会出现脏读