阅读本篇文章,首先要了解以下三个基础知识,有个大概的概念,这三个基础知识具体内容就不赘述了。
事务的基本要素
A 原子性、C 一致性、I 隔离性、D 持久性。
事务并发产生的问题
脏读,
不可重复读
幻读
mysql事务隔离级别
读未提交 RU read-uncommitted
读已提交 RC read-committed
可重复读 RR repeatable-read (mysql默认的隔离级别为 RR)
串行化 serializable
接下来会用sql来演示以上的内容
读未提交
事务A读取到了事务B未提交的数据。
首先,在开启两个query的窗口,都执行下面的两行sql
-
-- 先执行下,可以看到mysql默认的隔离级别是RR
-
select @@tx_isolation;
-
-
-- 设定当前session的隔离级别为RU
-
set
session
transaction
isolation
level
read uncommitted;
在第一个窗口中执行下面的语句(注意两个窗口,都按照注释中的step一行一行执行)
-
-- step 1.1 开启A事务
-
begin;
-
-- step 1.3 执行查询
-
select *
from
account;
-
-
-- step 1.5 再次执行查询,发现读取到了B事务中的更改
-
select *
from
account;
-
-
-- step 1.7 提交事务
-
commit;
在第二个窗口中执行下面的语句
-
-- step 1.2
-
begin;
-
-
-- step 1.4
-
update
account
set balance = balance -
50
where
id =
1;
-
-
-
-- step 1.6 回滚事务
-
rollback;
当执行到step 1.5,结果中可以看到事务A中,能查询到事务B未提交的事务。
如果后续step1.6中回滚了事务B,但是在这之前,事务A却拿着已更改的数据中间状态来处理后续的逻辑,就会造成脏读了,比如事务A也执行 balance - 50 的操作。那么最终的结果,id为1的数据从最开始的450变成了350,但是实际两个事务最终要的结果是只减少50.
以上就说明了,在RU隔离级别下,事务A能读取到事务B未提交的数据,导致了脏读。
读已提交
读已提交就是为了解决读未提交脏读的问题
修改两个query session的隔离级别为读已提交
-
-- 先执行下,可以看到mysql默认的隔离级别是RR
-
select @@tx_isolation;
-
-
-- 设定当前session的隔离级别为RC
-
set
session
transaction
isolation
level
read committed;
在两个窗口中,都开启事务 begin; 然后按照一下的顺序执行:
事务A开启事务后,执行查询语句,此时数据为450
事务B中,执行更新
事务A中再次执行查询,会发现数据仍为450,这就表示没有出现上面读未提交隔离级别中,读到事务B未提交的数据的情况
事务A执行更新,此时会发现执行阻塞了,因为此时事务B的更新操作,并没有提交,事务A获取不到锁
事务B一直不提交,那么事务A最终会锁超时,如下图所示
事务A的更新操作在执行过程中等待锁,这个时候事务B回滚事务,那么事务A会立即执行完成,最终结果id=1的数据balance是400。这样就说明了不会出现脏读导致的脏数据问题。
读已提交,解决了脏读的问题,但是会出现如下不可重复读的问题
事务A开启了事务,进行了一次查询此时的数据,仍旧是450。
然后,事务B开启了事务并且更新数据为400直接提交事务B。
事务A再次查询,就会发现数据已经变为了400。
在同一个事务A中,两次查询得到了不同的数据,这就是不可重复读的问题。
可重复读
可重复读就是来解决读已提交中的不可重复读的问题,保证在同一个事务中读取到的数据是一致的。
修改一下隔离级别
-
-- 先执行下,可以看到mysql默认的隔离级别是RR
-
select @@tx_isolation;
-
-
-- 设定当前session的隔离级别为RR
-
set
session
transaction
isolation
level repeatable
read ;
在事务A中,开启事务并查询,此时数据为300,也就生成了一份数据快照
在事务B中,开始事务并更新数据为350,提交事务
事务A中再次执行查询,发现数据仍为300,读取的仍旧是快照当中的内容,可以证明可重复读,解决了不可重复读的问题。
此时不要提交事务A,再开启事务B并且删除id=3的数据并提交事务
这个时候,事务A再次查询还是能够看到id=3的数据
此时,事务A仍旧没有提交,刚才在事务B中已经将id=1的数据更新为350并提交了,此时在事务A中,执行将id=1的数据 + 50,再次查询数据,会发现id=1的数据变成了400,这样数据的一致性就没有被破坏,原因是因为可重复度的隔离级别下,使用了MVCC机制,select操作是快照读,insert/update/delete是当前读。
但是,可重复读中会出现幻读的问题:
在开启事务A,查询
在事务B中,插入数据并提交
在事务A中查询,仍旧看不到lucy这条数据,但是执行插入id=4的数据,会报主键冲突,这也就是幻读的现象
幻读和不可重复读很容易混淆,只要记住不可重复读是针对修改和删除的,幻读是针对新增的即可。
如果你觉得这篇文章对你有帮助,请点击下方,一键三连
转载:https://blog.csdn.net/u010372981/article/details/108654950