事务隔离:为什么你改了我还看不见?
事务就是要保证一组数据库操作,要么全部成功,要么全部失败。在MySQL里,事务支持是在引擎层实现的。MySQL是一个支持多引擎的系统,但不是所有的引擎都支持事务,MySQL原生的MyISAM引擎就不支持事务。
事务的四个特性,ACID,即原子性、一致性、隔离性和持久性。
隔离性与隔离级别
当数据库上有多个事务同时执行的时候,可能会出现脏读、不可重复读、幻读的问题,为了解决问题,就有了“隔离级别”的概念。
首先要明确的一点是,你隔离得越严实,效率就会越低。因此很多时候,我们都需要在二者之间寻找一个平衡点。SQL标准的事务隔离级别包括下面几个:
- 读未提交
read uncommited
:一个事务还没提交时,它做的变更就能被别的事务看到 - 读提交
read commited
:一个事务提交以后,它做的变更才能被别的事务看到 - 可重复读
repeatable read
:一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。未提交变更对其他事务不可见。 - 串行化
serializable
:对于同一行记录,写会加写锁,读会加读锁。当出现读写锁冲突时,后访问的事务必须等前一个事务执行完成,才能继续执行。
假设数据表T中只有一列,其中一行的值为1,下面是按照时间顺序执行两个事务的行为:
mysql> create table T(c int) engine=InnoDB;
insert into T(c) values(1);
观察下在不同的隔离级别下,事务A会有哪些不同的返回结果,也就是图里V1/V2/V3的返回值分别是什么?
- 读未提交:虽然事务B还没有提交,但是结果已经被A看到了所以
V1=V2=V3=2
- 读提交:事务B的更新在提交以后才能被A看到,所以
V1=1,v2=v3=2
- 可重复读:事务A在执行期间看到的数据前后是一致的,所以
V1=V2=1,V3=2
- 串行化:当事务B执行“将1改成2”的时候,会被锁住。直到事务A提交后,事务B才继续执行。所以
v1=v2=1,v3=2