事务的隔离级别和引发的问题

以mysql为例:

查询当前事务的隔离级别用

select @@tx_isolation;

设置隔离级别用 set session transaction isolation level [隔离级别];

mysql的默认隔离级别为 Repeatable Read可重复读

oracle的默认隔离级别为Read Committed;读已提交

 

 

四种隔离级别:

Read Uncommitted:未提交读   

Read Committed :已提交读(oracle默认)

Repeatable Read:可重复读(mysql默认)

Serializable:序列化

 

 

Read Uncommitted  

事务的隔离级别和引发的问题

我们将左边的隔离级别设置为未提交读

可以看到,左右都开启了事务,但是右边更新数据之后还没有提交,左边就可以读取到右边为提交的数据

这就会引发脏读的问题

 

Read Committed  

事务的隔离级别和引发的问题

我们将左边的隔离级别设置为提交读

可以看到,左右都开启了事务,但是右边更新数据之后还没有提交,左边就不可以读取到右边未提交的数据

只有等右边的数据提交了,左边才能读取到

但是这样又有一个问题,就是左边还未提交,就能读取到另一个事务提交的数据

这就会引发不可重复读的问题

 

 

Repeatable Read

事务的隔离级别和引发的问题

左边数据太长了,只能截取一部分

我们将左边的隔离级别设置为可重复读

可以看到,左右都开启了事务,右边事务提交后的数据,只有左边的事务也提交之后才可以读取到

 

Serializable:序列化

事务的隔离级别和引发的问题

 

事务的隔离级别和引发的问题

我们将左边的隔离级别设置为序列化

我们这里先在左边开启事务,我们可以看到第一张图,左边事务先开启,右边的插入数据就无法执行

只有等左边的事务提交了,右边才能进行插入事务,如图二

假如我们将右边事务先开启,那么只有等右边的事务提交了,左边的操作才能进行

 

 

引发读的安全问题 

脏读:一个事务读取到了另一个事务为提交的内容,例如隔离级别为未提交读

不可重复读:一个事务读取到了另一个事务提交的数据,导致前后两次查询结果不一致,例如隔离级别为提交读

幻读:一个事务读取到另一个事务插入的数据,导致多次查询的结果不一致。也就是说第一次查询有n条记录,第二次查询有n+1条数据,看起来就像产生幻觉

 

 

效率

未提交读>提交读>可重复读>序列化

 

引发写的安全问题(隔离级别不是序列化的级别)

一般引发写的问题就是丢失更新的数据

事务的隔离级别和引发的问题

事务a,b开启事务后同时查询

然后事务a先对事务进行更新,事务b对事务后更新引发的问题

 

解决的方法一般两个:悲观锁和乐观锁

 

悲观锁

一般认为丢失更新一定会发生

在查询的时候加上字段 for update 

事务的隔离级别和引发的问题

a事务的查询加上for update后,b事务的界面就会卡主,拿不了数据,只能等a数据提交后才能拿数据

这样就保证了数据a提交的数据不会丢失

 

乐观锁

认为不会发生丢失更新,一般有程序员手动增加任意字段,一般加上version

事务的隔离级别和引发的问题

例如程序员手动加上了version字段,初始字段为version(0)

那么a事务和b事务一开始的version(0)

然后a事务修改了数据并提交,version(0)就会变成version(1),

b事务进行操作的时候发现version的值改变了,便会从数据库中重新查询数据

这样也能保证数据不会更新丢失。