事务隔离级别测试

2019-02-09  本文已影响0人  c108cb39fd41

MYSQL事务的四种隔离级别简介

读未提交

其他事务未提交的数据变更对本事务可见。

读已提交

其他事务未提交的数据变更对本事务不可见。

可重复读

在一次事务里,本事务对某行记录多次读取的结果是一致的,即使中间有其他事务提交了对该数据的变更。

序列化

多个事务之间必须串行执行,事务之间的操作不可交叉。

——————————————————————

|  隔离级别  |     脏读     |   不可重复读   |    幻读    |

——————————————————————

|读未提交    |       Y        |           Y           |      Y      |   

——————————————————————

|读已提交    |      X        |            Y           |        Y    |

——————————————————————

|可重复读    |      X        |            X            |        Y   |

——————————————————————

|序列化       |      X        |            X            |        X    |

测试

测试数据准备

CREATE TABLE `People` (

  `ID` bigint(20) NOT NULL,

  `Name` varchar(255) NOT NULL,

  `Age` int(11) NOT NULL

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `People` (`ID`, `Name`, `Age`)

VALUES (1, '炒饭', 31),(2, '阿丹', 33)

脏读

事务1    set session transaction isolation level read uncommitted

事务1    start transaction

事务2    start transaction

事务2    update People set Age=32 where ID=1;

事务1   select * from People where ID=1; 结果

事务1读到了事务2未提交的数据变更

解决脏读需要事务1设置隔离级别为读提交read committed

set session transaction isolation level read committed

不可重复读

事务1    set session transaction isolation level read committed

事务1    start transaction

事务2    start transaction

事务1    select * from People where ID=1; 结果

事务2     update People set Age=33 where ID=1;

事务2     commit;

事务1     select * from People where ID=1; 结果

事务1第一次查询ID=1的记录跟第二次查询结果不一样,称为不可重复读

解决不可重复读需要设置隔离级别为可重复读

set session transaction isolation level read repeatable read

幻读

幻读,并不是说两次读取获取的结果集不同(可重复读级别已经解决该问题),幻读侧重的方面是某一次的 select 操作得到的结果所表征的数据状态无法支撑后续的业务操作。更为具体一些:select 某记录是否存在,不存在,准备插入此记录,但执行 insert 时发现此记录已存在,无法插入,此时就发生了幻读。(很多人对幻读有误解,个人认同这个作者的观点 https://segmentfault.com/a/1190000016566788)

事务1    set session transaction isolation level repeatable read

事务1    start transaction

事务2   start transaction

事务1    select * from People where ID=1

事务2   insert into People (ID,Name,Age) values(1,'西西',15)

事务1    如果select记录不存在,执行insert into People (ID,Name,Age) values(1,'西西',15)

事务2   commit;

事务1   commit;

事务1希望ID=1的记录不存在时去执行插入操作,然而事务2先插入了记录,事务1又插入了一次记录,仿佛之前事务1的select看到的跟幻觉一样。

在可重复读隔离级别下,避免幻读,可以用select * from People where ID=1 for update,加上行锁,能保证当前事务不受其他事务的写入干扰。

上一篇下一篇

猜你喜欢

热点阅读