Mysql事物隔离级别
MYSQL事物隔离级别是面试经常问的,也是MYSQL中必须要了解的一个知识点,本篇文章主要理解事物隔离级别以及每种隔离级别下会发生什么问题?下面我们一起来看下。
事物四大特性【ACID】
-
A:原子性【Atomicity】:一个事物中所有的SQL脚本要么全都执行成功,要么全都执行失败【undo log实现】。
-
C:一致性【Consistency】:事物执行完之后,必须保证数据完整性【redo log实现】。
-
I:隔离性【Isolation】:事物和事物之间执行不受影响,数据库引擎不同底层实现也不同【MyISAM不支持事物,InnoDB主要通过MVCC和数据库读写锁实现】。
-
D:持久性【Durability】:事物执行成功后,会立马写到磁盘中,且必须保证最终一致性。
事物隔离级别
查看事物隔离级别
-- 查看全局隔离级别,和当前会话隔离级别
SELECT @@GLOBAL.tx_isolation, @@tx_isolation;
-- 设置默认隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
实践测试表
CREATE TABLE `transaction_test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4
-
读未提交【READ UNCOMMITTED】
字面意思理解即可,就是在多个事物当中,可以互相读去对方未提交的数据。
可以先动手操作下,后边再看结论。-- 设置当前会话隔离级别 SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED -- 手动开启一个事物 START TRANSACTION; INSERT INTO `shac_rps`.`transaction_test` ( `name`, `age`) VALUES ( 'jay', 22); -- 先别提交 COMMIT; -- 可在当前会话执行查看,也开从新开一个会话,但需要先设置隔离级别 select * from transaction_test
执行过程如截图:
修改默认事物隔离级别,这个SQL改的是当前会话的事物隔离级别。
然后起一个事物执行一个insert,但不执行commit。
开启第二个会话,修改事物隔离级别,再执行select发现结果能查询到未提交数据
如果数据库设置了这个事物隔离级别,在代码中很容易出现脏读问题。
脏读:当一个事物能读到另一个事物未提交的数据就说明出现脏读了。例如:当A事物在update某条数据时,当前事物并没有执行完,但此时事物B需要用到,并且去数据库查这条事物A修改了但未提交的数据去做业务,拿到的数据就是事物A修改后的数据,但事物A后边执行过程中出现异常,导致事物回滚,那事物B拿的数据就是脏数据,做的业务也有问题。
大概理解什么是脏读以及脏数据,但实际上不可能这么简单的。
-
读已提交【READ COMMITTED】
在多个事物执行当中,能读到对方已提交的数据。在代码中相当于一个方法里 执行多次查询得出来的结果不一样。先操作再说结论。
-- 记得设置级别 SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED -- 重新起一个事物 START TRANSACTION; select * from transaction_test where id <10 -- 等其他事物执行完insert之后再执行 select * from transaction_test where id <10 COMMIT; -- 其他会话 INSERT INTO `shac_rps`.`transaction_test` ( `name`, `age`) VALUES ( 'marry', 22);
我们起一个事物开始第一次查询
第二个会话插入一条新数据
然后回到第一个会话执行第二次查询语句,结果如下
如结果所示,同一个事物中,相同查询条件,查询数据结果集不一样!
所以读已提交事物隔离级别容易造成幻读和不可重复读问题。
下面我们来详细讲一下幻读和不可重复读!
幻读:同一个事物在查询多次数据时,出现行数不同就说明出现幻读了。例如:事物A在第一次根据查询条件查出数据条数10条,此时事物B执行了insert,刚好也满足事物的查询条件,事物B提交后,事物A再次同样的查询条件查询数据发现数据跟第一次数据量不一致。这就是幻读。
至于什么样的业务会选择这种提交方式,就得看业务场景了。
幻读理解总结:在同一个事物中同样的查询条件查询多次得出的查询结果条数不同,就是幻读。
不可能重复读:同一个事物中查询多次数据时,数据内容结果出现不同时就是不可重复读。
例如:事物A第一次根据某条件查询数据,然后去执行业务,事物A未提交之前,事物B修改了这批数据且提交了,然后事物A再次同条件查询数据,发现两次数据内容结果不同,此时就出现不可重复读!
就拿id为1的这条数据作为例子,先起一个事物A,第一次查询
事物B更新事物A中的数据
事物A相同条件再次查询数据
发现结果被事物B修改,所以读已提交会导致不可重复读!
大概执行流程如下:
幻读和不可重复读总结:幻读是同一个事物中多次查询结果条数不同,不可重复读是同一个事物中根据某个查询条件查询多次数据内容结果不同。
-
可重复读【REPEATABLE READ,默认】
可重复读是MYSQL默认隔离级别。MYSQL可重复读是通过MVCC来实现的【具体需要去了解MVCC实现原理】,对于可重复读来说,每次执行事物都会有事物id,通过比较事物id来实现事物的隔离,也叫做多版本控制。
在测试过程中,一般情况下是可以防止幻读问题的。以下有几种情况会发生幻读问题:
- 在同一个事物中执行两次select,第二次select手动加一个锁 for share或for update,就可以查到其他事物提交的数据
- 在同一个事物中ddl语句也会影响查询结果,具体可以看下面博客解析了可重复读可能会有幻读情况。
详情URL:
https://blog.csdn.net/rsjssc/article/details/123465816
-
串行读【SERIALIZABLE】
当发生读写锁冲突时,后面的事务要等前面的事务执行完毕之后再执行,所以一定是先读或者先写的执行完毕之后再执行后读或者写,读写按照顺序依次进行,所以
不存在脏读
、不存在不可重复读
、也不存在幻读
。最后总结下: