MySQL事务隔离级别

MySQL 四种隔离级别

我们知道事务的四大特性分别为:

原子性 A(Atomicity)
一致性 C(Consistency)
隔离性 I(Isolation) 
持久性 D(Durability)

既然存在隔离性,为什么又有隔离级别。

事务执行过程中不受其他事务影响,这个是事务的隔离性

但是多事务操作的数据是同一份,就有冲突存在的可能,为了避免这种问题,我们使用隔离级别

隔离级别应用场景

Read Uncommitted(读取未提交内容) -- 导致:脏读、不可重复读 、幻读or虚读

一个事务读取其他事务未提交的内容,一旦其他事务回滚,就会导致读取到脏数据;
实际场景很少用,因为性能提升不大(可以切换存储引擎例如MyISAM,性能极佳,不支持事务)

Read Committed(读取提交内容) -- 导致:不可重复读 、幻读or虚读

大多数数据库系统的默认隔离级别(但不是MySQL默认的);只能读取其他事务已经提交的数据;
一个事务读取一个数据后,再次读取的时候,该数据可能会被其他事务更新提交,造成两次读取不一致(乐观锁?)。

Repeatable Read(可重读) -- 导致:幻读or虚读

MySQL默认隔离级别,同一个事务在多次读取数据时,会看到同样结果;
读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。

Serializable(可串行化) -- 导致:超时、死锁

这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。

测试隔离级别

创建test表

id money
1 100

Read UNCOMMITTED

Session A 
    set session transaction isolation level read UNCOMMITTED; -- 设置会话隔离级别为读未提交
    select @@tx_isolation  -- select @@transaction_isolation (mysql版本 8.0 以后)
    start TRANSACTION;
Session B
    start TRANSACTION; 
    update test set money = 1001 where id = 1;
Session A
    select * from test;

结果:Session A 读取到了Session B未提交的脏数据

Read COMMITTED

Session A 
    set session transaction isolation level read COMMITTED; -- 设置会话隔离级别为读已提交
    select @@tx_isolation 
    start TRANSACTION;
Session B
    start TRANSACTION; 
    update test set money = 1001 where id = 1;
Session A
	select * from test;
Session B
	COMMIT;
Session A
	select * from test;	

结果:Session A 分别读取了Session B提交事务前后两个不同的数据

Repeatable Read (深入了解MVCC)

Session A 
    set session transaction isolation level Repeatable Read;
    select @@tx_isolation;
    start TRANSACTION;
Session B    
    start TRANSACTION;
    update test set money = 1001 where id = 1;
Session A 
	select * from test;
Session B 
	COMMIT;
Session A 
	select * from test;

结果:Session A 两次读取结果一致

SERIALIZABLE (锁)

select * from information_schema.innodb_trx; -- 可以使用本语句查询未提交事务的基本信息,只有执行了sql语句的事务,才会存在该表;下文简称事务列表

kill trx_mysql_thread_id(上行语句返回的字段) --强制关闭某个事务

Session A 
   set session transaction isolation level SERIALIZABLE;
	select @@tx_isolation;
	start TRANSACTION;
	-- 事务列表0条
Session B    
    start TRANSACTION;
    update test set money = 1001 where id = 1;
    -- 事务列表1条 
Session A 
	select * from test;
	-- 事务列表2条,本事务进入阻塞状态 如下表所示
Session B 
	COMMIT;
	-- 事务列表1 条
	-- Session A解除阻塞,获取更新后的结果
Session A 
	COMMIT;
	-- 事务列表0条
trx_id trx_state tx_mysql_thread_id trx_query trx_isolation_level
4AC LOCK WAIT 485 select * from test REPEATABLE READ
4AB RUNNING 486 null SERIALIZABLE

MySQL事务隔离级别

上一篇:oracle查看执行计划


下一篇:grafana+ prometheus+php 监控系统实践