彻底搞懂mysql隔离级别和事务
前言
我们都知道,mysql的InnoDB存储引擎支持事务操作,事务ACID特性中的隔离性可以使当前事务中的操作不受其他事务操作的影响,然而,这个隔离性是和隔离级别相关的特性,不同的隔离级别对隔离的严格性不同,对不同的隔离级别一一实验后,我们会发现,如果单单说事务的隔离性不受其他事务的影响,这句话是不太准确的,或者说是不严谨的说法。作为一个工科,我觉得能看到一个示例,比单纯看理论更能让人理解、记忆深刻。
一、查看和设置当前的隔离级别:
我们先登录mysql终端,查看和设置当前的隔离级别:
mysql> show variables like '%isolation%';
+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| tx_isolation | REPEATABLE-READ | //mysql默认的是RR的隔离级别
+---------------+-----------------+
1 row in set (0.00 sec)
或者执行以下命令:
mysql> select @@global.tx_isolation, @@tx_isolation;
+-----------------------+-----------------+
| @@global.tx_isolation | @@tx_isolation |
+-----------------------+-----------------+
| REPEATABLE-READ | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set (0.00 sec)
// 修改事务隔离级别:
可以 help ISOLATION 查看一下都有哪些隔离级别,或者直接
set session transaction isolation level 事务隔离级别,如设置成RU隔离级别:
set session transaction isolation level READ UNCOMMITTED;
二、两个事务的比较
注意: 事务回退之后,自增id也会隐形加1 ,例如回退的那行的id是3,那么下次再添加的时候,id就会变成4了
(1)隔离级别是RU(未提交读)
未提交读: 是指开启的两个事务,如果一个事务修改了内容,那么即使没有提交,在另一个事务中也能看到改动 。
a)insert: 事务不会阻塞,各个事务进行各自的插入,插入的数据不管提不提交 ,都能被另一个事务看到,所以也叫未提交读
比如开启一个事务A 和 事务B:
b)update: 更新同一行数据,事务会阻塞,超时,被阻塞的事务会退出事务;但是更新不是同一行,那么和insert情形一致。
(i)更新同一行的情形
(j)更新不是同一行的情形
select: 有影响,因为未提交读,所以同样的查询条件 的结果可能都不一样。
这里也会出现脏读、幻读和不可重复读。
(个人以为,其实脏读、幻读、不可重复读没有什么明显的界限区别,都是同样的查询导致不同的结果,你可以说这是脏读、也可以说是幻读,还可以说是不可重复读!只不过是由于查询的范围不同,导致不同的名称,如下:
脏读: 一般是查询一条或几条特定的数据,由于其他事务的干扰,不管是否提交,我们再次查询时,会查询到被修改(被污染)的数据。
幻读: 一般是查询范围时,由于其他事务的干扰,不管是否提交,我们再次查询这个范围时,可能会多查出或少查出几条数据,就好像发生了幻觉一样
可重复和不可重复读: 这个主要是指 多个事务当中,其中一个事务做了修改且已提交,那么在其他的事务当中,查询被修改的这条记录,如果每次查询的都是已修改后的数据,说明同样的查询得到不同的查询结果,查询结果是不重复的,所以也叫不可重复读; 可重复读相反,每次查询的结果都是修改前的结果,所以也叫可重复读! 一般来说,可重复和不可重复,主要是针对RC和RR的隔离级别的。
个人观点,大佬勿喷!)
delete: 删除同一行数据,事务会阻塞,超时,被阻塞的sql失效; 如果删除不是同一行数据,那么和insert情形一致
(i)删除同一行
(j)删除不是同一行
(2)隔离级别是RC (提交读 或不可重复读)
两个事务虽然有共同的操作,但在都没有提交之前互不影响,自己进行自己的查询更新等操作,但是一旦有个事务提交,那么另一个事务就会收到影响。
insert: 事务不会阻塞,事务在提交之前,另一个事务是不会看到改动的,但是第一个事务一旦提交,另一个事务不管提不提交都会看到改动
update: 更新同一行数据,事务会阻塞,超时,被阻塞的事务会退出事务;如果更新不是同一行数据,那么和insert的情形一致。
select: 在两个事务提交之前,查询的都是事务开启之前的数据,一旦有一个事务提交,那么不管另一个事务是否提交,查询的都是最新的那个事务的提交结果, 也即是不可重复读
delete: 删除同一行数据,事务会阻塞,超时,被阻塞的sql失效;如果删除的不是同一行,那么和insert情形一致。
(3)隔离级别是RR (可重复读)
insert: 事务不会阻塞,事务在提交之前,另一个事务是不会看到改动的,即使是第一个事务提交,另一个事务如果不提交,那么也看不到第一个事务提交的结果,在本事务中,每次查询都是返回同样的结果,所以也叫 可重复读。
update: 更新同一行数据,事务会阻塞,超时,被阻塞的sql失效;如果不是更新同一行,那么和insert情形一致。
select: 事务的修改互不影响, 可重复读,这个隔离级别也解决了幻读(通过MVCC机制取快照读的方式)的问题。
delete: 删除同一行数据,事务会阻塞,超时,被阻塞的sql会失效;如果删除的不是同一行,那么的insert的情形一致。
(4)隔离级别是 serializable (可串行化) -- 这个隔离级别相当于 表锁
insert: 事务不会阻塞,可以正常在事务内insert, 但是select的时候会阻塞,另一个事务如果也select,会造成死锁回滚
update: 更新即使不是同一行,也会相互阻塞
select: 两个事务查询会相互阻塞
delete: 删除不是同一行数据,也会相互阻塞
这个隔离级别是最严格的隔离级别,所以我们可以得出一个结论:
serializable的隔离级别下: 一个事务开启的时候,另一个事务除了insert以外, select、update、delete操作都会阻塞