MySql事务隔离级别
这里我们仅介绍MySql事务隔离级别,对于一些关于事务的概念不在做介绍
mysql当中的隔离级别一共有四种分别是
- Read Uncommitted(读取未提交内容)
- Read Committed(读取提交内容)
- Repeatable Read(可重读)
- Serializable(可串行化)
下面我们分别介绍这四种隔离级别的影响
首先我们创建一个简单的表
create table t(
id int,
name varchar(20)
)ENGINE=INNODB;
新增一些数据
insert into t values(3,'zhou');
insert into t values(5,'wen');
insert into t values(7,'xiang');
Read Uncommitted(读取未提交内容)
我们开启两个会话
步骤如图
对上图我们来做一个简单的分析会话B的隔离级别设置为read uncommitted的情况下
会话A启动事务A会话B启动事务B,并且在t表新增一条数据但是未提交,这时在会话B能够查询出会话B提交的数据,也就是说会话B能够看到会话A的修改结果。
问题:这样会导致一脏读的数据
Read Committed(读取提交内容)
同样我们开启两个会话
由上图可以看出,会话B的事务隔离级别设置为read committed后。
会话A中开启的事务A,在修改数据后,但是未提交的情况下,会话B中的事务B无法查询到更新的数据,
在步骤9之后也就是事务A提交之后,事务B能够查询到事务A修改的数据
由此可见事务隔离级别进一步降低了数据脏读的可能性。
Repeatable Read(可重读)
将事务隔离级别设置为可重复读的情况下,两个事务之间可以达到理想隔离状态,事务之前的操作互不影响
同样我们举个例子,开启两个会话,进行一系列操作,并分析其步骤,结果如下图
由上图可知,会话A和会话B同时开启事务,在事务A中对t表的操作不管有没有提交,在事务B中只要事务B不提交就无法查询到会话A中对t表的修改。
由上可知repeatable read 可以达到一个理想的事务隔离级别。
Serializable(可串行化)
现在我们测试下将事务的隔离级别设置为serializable级别的情形,
同样我们开启两个会话,并且启动两个事务,并分析其步骤和结果,如下图
这里我们可以看到,两个会话可以同时读取t表数据,但是事务A开始修改t表数据时,会处于阻塞状态,需要等事务B释放锁,假如这个时候事务B也对t表进行修改,那么会导致死锁,事务B结束释放锁,事务A更新完成。
由此可知serializable会把innodb的锁级别由行级提升到表级。
serializable的模式比较严格,一般场景下不需要提高的这个级别。
以上我们介绍了事务隔离级别的影响,下面我们来介绍下锁在使用innodb作为engine的情况
这里我们按操作类型来介绍锁,分为读锁和写锁
注意MySql如果表中没有索引或者查询或者更新的时候没有使用索引那么将由行锁变为表锁。
我们下面来看下锁的互斥情况
读锁和读锁可以共享,不互斥
我们看下下面数据的执行情况
事务A的查询和事务B的查询互补影响,可以同时进行
读锁和写锁互斥,各自需要先得到锁的那一方释放锁才能执行。
下面我们开启事务A和事务B,事务A先使用写锁锁定id为3行数据,事务B使用读锁锁定id为3行数据,运行结果如下
可以看到事务B的查询花了18秒时间,其需要等到事务A提交了之后才能获得锁,进而查询到结果。
读锁和读锁互斥,各自需要先得到锁的那一方释放锁才能执行。
下面我们开启事务A和事务B,事务A先使用写锁锁定id为3行数据,事务B使用写锁锁定id为3行数据,运行结果如下
可以看到事务B的查询话费了15秒的时间,也就是需要等到事务A提交了之后,才能获得锁。
对于锁的总结是,MySql当中使用Innodb的时候,如果没有索引或者sql语句中没有使用索引行锁将会转换为表锁,读锁和读锁共享,写锁和读锁和写锁不共享互斥。