隔离级别
读未提交(READ UNCOMMITTED)
A事务与B事务,A事务可以读取到B事务未提交的数据。这是最低的隔离级别。几乎两个事务之间没有隔离。这种隔离级别是一种理论层面的,在实际的数据库产品中,没有从这个级别起步的。
当事务隔离级别是读未提交时,三种现象都存在:脏读,不可重复读,幻读。
我们可以开启两个DOS命令窗口,模拟两个事务,演示一下这种隔离级别。三种现象中最严重的是脏读,我们只需要演示脏读问题即可,因为存在脏读的话,就一定存在不可重复读和幻读问题。
将全局事务隔离级别设置为:READ UNCOMMITTED
set global transaction isolation level read uncommitted;
开启两个DOS命令窗口来模拟两个事务:A事务与B事务。
演示:
A事务 | B事务 |
---|---|
mysql> use powernode | |
mysql> use powernode | |
mysql> start transaction; | |
mysql> start transaction; | |
mysql> select * from a; | |
![]() | |
mysql> insert into a values(4); | |
mysql> select * from a; | |
![]() |
通过以上测试,可以看到,A事务读取到了B事务还没有提交的数据。这种现象就是脏读。
读提交(READ COMMITTED)
A事务与B事务,A事务可以读取到B事务提交之后的数据。Oracle数据库默认的就是这种隔离级别。
将数据库的全局事务隔离级别设置为读提交:READ COMMITTED
set global transaction isolation level read committed;
演示:
A事务 | B事务 |
---|---|
mysql> use powernode | |
mysql> use powernode | |
mysql> start transaction; | |
mysql> start transaction; | |
mysql> select * from a; | |
![]() | |
mysql> insert into a values(4); | |
mysql> select * from a; | |
![]() | |
mysql> commit; | |
mysql> select * from a; | |
![]() |
通过以上测试看出,A事务只能读取到B事务提交之后的数据。这种隔离级别解决了脏读问题,但肯定是存在不可重复读和幻读问题。因为只要事务B进行了增删改操作之后并提交了,事务A读取到的数据肯定是不同的。即:不可重复读和幻读都存在。
可重复读(REPEATABLE READ)
这个隔离级别是MySQL数据库默认的。
A事务和B事务,A事务开启后,读取了某一条记录,然后B事务对这条记录进行修改并提交,A事务读取到的还是修改前的数据。这种隔离级别称为可重复读。
将数据库全局隔离级别修改为可重复读:
set global transaction isolation level repeatable read;
演示:
事务A | 事务B |
---|---|
mysql> use powernode | |
mysql> use powernode | |
mysql> start transaction; | |
mysql> start transaction; | |
mysql> select empno,ename,sal from emp where empno=7369; | |
![]() | |
mysql> update emp set ename='SMITH',sal=8000 where empno=7369; | |
mysql> commit; | |
mysql> select empno,ename,sal from emp where empno=7369; | |
![]() |
通过以上测试得知:当事务隔离级别设置为可重复读时,避免了不可重复读问题。
那么在MySQL当中,当事务隔离级别设置为可重复读时,能够避免幻读问题吗?测试一下:
事务A | 事务B |
---|---|
mysql> use powernode | |
mysql> use powernode | |
mysql> start transaction; | |
mysql> start transaction; | |
mysql> select * from a; | |
![]() | |
mysql> insert into a values(5); | |
mysql> commit; | |
mysql> select * from a; | |
![]() |
通过以上测试得知:当事务隔离级别设置为可重复读时,也避免了幻读问题。是完全避免了幻读问题吗?并不是。请看以下测试:
事务A | 事务B |
---|---|
mysql> use powernode | |
mysql> use powernode | |
mysql> start transaction; | |
mysql> start transaction; | |
mysql> select * from a; | |
![]() | |
mysql> insert into a values(6); | |
mysql> commit; | |
mysql> select * from a for update; | |
![]() |
通过以上测试得知:当事务隔离级别设置为可重复读,MySQL会尽最大努力避免幻读问题,但这种隔离级别无法完全避免幻读问题。
串行化(SERIALIZABLE)
这种隔离级别最高,避免了所有的问题,缺点是效率低,因为这种隔离级别会导致事务排队处理,不支持并发。
设置数据库全局隔离级别为串行化:
set global transaction isolation level serializable;
演示:
事务A | 事务B |
---|---|
mysql> use powernode | |
mysql> use powernode | |
mysql> start transaction; | |
mysql> start transaction; | |
mysql> select * from a; | |
![]() | |
mysql> insert into a values(7); | |
mysql> select * from a; | |
![]() | |
mysql> commit; | |
![]() |
通过以上测试得知:当事务隔离级别设置为串行化时,事务只能排队执行,不支持并发。