数据库的隔离级别

Read Uncommitted

读未提交,一个事务可以读取另一个未提交事务的数据。

A事务

B事务

begin

begin

update goods set price=2.0 where id=1

select price from goods where id=1; 此时能读取到price为2.0

update goods set price=price+2.0; 此时更新的价格的时候,对方可能回滚了,造成了数据不一致

rollback

commit

A事务未提交的时候,B事务可以读取到A事务修改的内容,这就是脏读

如何解决脏读?Read Committed

Read Committed

读提交,一个事务要等另一个事务提交后才能读取数据。

A事务

B事务

select price from goods where id = 1; 此时价格为1.0

begin

begin

update goods set price=2.0 where id=1

select price from goods where id=1; 此时能读取到price为1.0

commit

select price from goods where id=1; 此时能读取到price为2.0

commit

A事务开启的时候,B事务也同时开启,此时A事务更新价格为price为2.0,但是还没有commit,B事务读取到的价格依然是1.0,在A事务提交后,B事务再次读取,读取到的为A事务更新后的2.0。

但是此时的B事务并没有结束,而且在B事务中连续两次读取的价格不一致,这就是不可重复读的问题,Oracle,SQL Server目前采用的是这种隔离级别。

如何解决不可重复的问题,MySQL采用了 Repeatable Read

Repeatable Read

可重复读,在同一个事务内的查询都是事务开始时刻一致的

A事务

B事务

begin

begin

select price from goods where id = 1; 此时价格为1.0

update goods set price=2.0 where id=1

select price from goods where id=1; 此时能读取到的price还是1.0

commit

select price from goods where id=1; 此时能读取到的price依然为1.0

commit

select price from goods where id=1; 此时读到的price为2.0

在可重复读隔离级别下,事务B只能在事务A修改过数据并提交后,自己也提交事务后,才能读取到事务B修改的数据。

MySQL的可重复读操作,是采用的MVCC(Multi-Version Concurrency Control 多版本并发控制)实现隔离,对每行数据后添加两个额外的版本号值,每行记录的后面保存了两个隐藏的列, DB_TRX_ID(数据行的版本号)DB_ROLL_PT(删除版本号),这两列保存的是系统版本号,每开始一个新的事务,系统版本号都会自动递增。事务开始时刻的系统版本号会作为事务的版本号,用来和查询到的每行记录的版本号进行比较。开启某个事务后,会在Undo log中记录当前事务版本号的数据(快照读),读取自身的版本号内的数据,对于不同的操作,采用的版本号策略如下

  • SELECT,创建版本号 <= 当前事务版本号,删除版本号为空或>当前事务版本号。
  • INSERT,保存当前事务版本号为行的创建版本号
  • DELETE,保存当前事务版本号为行的删除版本号
  • UPDATE,插入一条新纪录,保存当前事务版本号为行创建版本号,同时保存当前事务版本号到原来删除的行

通过版本的控制,再从日志中读取旧版的数据,达到了行级别的隔离。

但是 insert数据直接创建了新的版本号,这就导致了select的时候,能够读取到insert进来的版本号的数据,这就是幻读

如何解决不可重复的问题,那就是serializable,串行化

Serializable

完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞。

在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读。但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用。

Author: Gavin Zhao
Link: https://www.gavinz.xyz/2021/07/15/数据库的隔离级别以及如何选择/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.