事务隔离级别
本文主要对事务隔离级别做测试,以加深对隔离级别的理解。
预备操作
-- 建表
create table t_user
(
id int auto_increment
primary key,
name varchar(255) null,
age int default 0 null,
status int default 1 null
);
-- 数据准备
insert into t_user(name, age, status) value ('zs', 11, 1);
insert into t_user(name, age, status) value ('ls', 18, 1);
-- 常用操作:修改隔离级别 session/global
set session transaction isolation level read uncommitted ; -- 读未提交
set session transaction isolation level read committed; -- 读已提交
set session transaction isolation level repeatable read; -- 可重复读
set session transaction isolation level serializable ; -- 序列化
-- 常用操作:查看隔离级别
show variables like 'transaction_isolation';
SELECT @@transaction_isolation;
读未提交
设置A和B的隔离级别为读未提交。
set session transaction isolation level read uncommitted ; -- 读未提交
操作:B开启事务,修改数据后,A去查询,然后B回滚。
-- sessionA
select * from t_user where id = 1; -- 顺序3
-- sessionB
begin; -- 顺序1
update t_user set age = 88 where id = 1; -- 顺序2
rollback ; -- 顺序4
结果:A查询到age=88,B回滚后,age=11。此时A查询到了B未提交的数据,产生了脏读。
读已提交
设置A和B的隔离级别为读已提交
set session transaction isolation level read committed; -- 读已提交
操作:还是按照读未提交测试的步骤
结果:A查询到age=11并非88,A读到的还是未提交前的数据。所以,读已提交解决了脏读问题。
操作:A开始事务,B修改数据并提交,A查询该数据,B再次修改数据并提交,A再次查询该数据。
-- sessionA
begin; -- 顺序1
select * from t_user where id = 1; -- 3
select * from t_user where id = 1; -- 5
commit;
-- sessionB
-- 顺序2
begin;
update t_user set age = 88 where id = 1;
commit;
-- 顺序4
begin;
update t_user set age = 77 where id = 1;
commit;
结果:A第一次查询age=88,第二次查询age=77,一次事务读取的结果不一样,产生了不可重复读。
可重复读
设置A和B隔离级别为可重复读
set session transaction isolation level repeatable read; -- 可重复读
操作:还是按照读未提交测试的步骤
结果:A两次查询age都是为88。所以,读已提交解决了不可重复读的问题。
操作2:A开启事务,根据id查询某条数据,B插入了一条id相同的数据,A再次根据id查询数据,如果为空则该id插入一条数据
-- sessionA
begin; -- 顺序1
select * from t_user where id=3; -- 顺序2
select * from t_user where id=3; -- 顺序4
insert into t_user set id=3, `name`='ww', age=25, status=1; -- 顺序5
commit;
-- sessionB
-- 顺序3
begin;
insert into t_user set id=3, `name`='ww', age=25, status=1;
commit;
结果:A两次查询结果都是空,A以为可以安全插入数据,结果报主键重复问题,产生了幻觉。所以读已提交不能解决幻读的问题。
序列化
设置A和B隔离级别为可序列化
set session transaction isolation level serializable ; -- 序列化
操作:还是按照可重复读测试的步骤
结果:A开启事务后,B尝试插入一条记录,一直在等待,无法插入,原因是序列化用的级别最高的表锁。虽然序列化解决了幻读问题,但性能堪忧。