mysql 隔离级别
隔离级别
mysql的事务隔离级别有四种,分别是读未提交、读已提交、可重复读、序列化,不同的隔离级别下会产生脏读、幻读、不可重复读等相关问题,因此在选择隔离级别的时候要根据应用场景来决定,使用合适的隔离级别:
READ UNCOMMITTED(未提交读),事务中的修改,即使没有提交,对其他事务也是可见的。事务能够读取未提交的数据,这种情况称为脏读
READ COMMITTED(读已提交),一个事务开始时,只能“看见”已经提交的事务所做的修改。有时候提交读也叫不可重复读(nonrepeatable read)
REPEATABLE READ(可重复读),同一个事务中,多次读取同样记录的结果是一致的。mysql默认的隔离级别
SERIALIZABLE(可串行化),最高隔离级别,完全服从ACID的隔离级别,读取每一行数据都加上锁,可能导致大量的超时和锁争用问题,一般不使用
各种隔离级别和数据库异常情况对应情况如下:
隔离级别 | 脏读可能性 | 不可重复读可能性 | 幻读可能性 | 加锁度 |
---|---|---|---|---|
READ UNCOMMITTED | Y | Y | Y | N |
READ COMMITTED | N | Y | Y | N |
REPEATABLE READ | N | N | Y | N |
SERIALIZABLE | N | N | N | Y |
脏读(Dirty Read):事务可以读取未提交的数据
不可重复读(nonrepeatable read)也叫虚读:前后读取的记录数可能不一致。事务A在第一次读取记录为5,然后事务B执行了更改为10.事务A在第二次读取记录为10
幻读(Phantom Read):当某个事务A在读取某个范围内的记录时,另外一个事务B又在该范围插入新的记录,当事务A再次读取该范围的记录时,会产生幻行
事务测试
1、打开mysql的命令行,将自动提交事务给关闭
--查看是否是自动提交 1表示开启,0表示关闭
select @@autocommit;
--设置关闭
set autocommit = 0;
2、数据准备
--创建数据库
create database tran;
--切换数据库 两个窗口都执行
use tran;
--准备数据
create table psn(id int primary key,name varchar(10)) engine=innodb;
--插入数据
insert into psn values(1,'zhangsan');
insert into psn values(2,'lisi');
insert into psn values(3,'wangwu');
commit;
3、测试事务
--事务包含四个隔离级别:从上往下,隔离级别越来越高,意味着数据越来越安全
read uncommitted; --读未提交
read commited; --读已提交
repeatable read; --可重复读
(seariable) --序列化执行,串行执行
--产生数据不一致的情况:
脏读
不可重复读
幻读
4、测试1:脏读 read uncommitted
set session transaction isolation level read uncommitted;
A:start transaction;
A:select * from psn;
B:start transaction;
B:select * from psn;
A:update psn set name='test';
A:selecet * from psn
B:select * from psn; --读取的结果test。产生脏读,因为A事务并没有commit,读取到了不存在的数据
A:commit;
B:select * from psn; --读取的数据是msb,因为A事务已经commit,数据永久的被修改
5、测试2:当使用read committed的时候,就不会出现脏读的情况了,当时会出现不可重复读的问题
set session transaction isolation level read committed;
A:start transaction;
A:select * from psn;
B:start transaction;
B:select * from psn;
--执行到此处的时候发现,两个窗口读取的数据是一致的
A:update psn set name ='zhangsan' where id = 1;
A:select * from psn;
B:select * from psn;
--执行到此处发现两个窗口读取的数据不一致,B窗口中读取不到更新的数据
A:commit;
A:select * from psn;--读取到更新的数据
B:select * from psn;--也读取到更新的数据
--发现同一个事务中多次读取数据出现不一致的情况
6、测试3:当使用repeatable read的时候(按照上面的步骤操作),就不会出现不可重复读的问题,但是会出现幻读的问题
set session transaction isolation level repeatable read;
A:start transaction;
A:select * from psn;
B:start transaction;
B:select * from psn;
--此时两个窗口读取的数据是一致的
A:insert into psn values(4,'sisi');
A:commit;
A:select * from psn;--读取到添加的数据
B:select * from psn;--读取不到添加的数据
B:insert into psn values(4,'sisi');--报错,无法插入数据
--此时发现读取不到数据,但是在插入的时候不允许插入,出现了幻读,设置更高级别的隔离级别即可解决