it编程 > 数据库 > Mysql

MySQL数据库事务的ACID之隔离性实验

81人参与 • 2026-09-29 • Mysql

acid特性简介

隔离性(isolation)

这个特性是通过事务隔离级别来实现的,不同的隔离级别能够解决不同的并发事务中的问题,但同时也会在性能和一致性之间做出权衡。

下面对该问题进行实验:

读未提交(read uncommitted)

首先,查看数据库事务隔离级别,并将隔离级别设置为读未提交。

使用如下命令查看事务隔离级别。

select @@session.transaction_isolation;

查询到隔离级别为可重复读。

设置隔离级别为读未提交。

set session transaction isolation level read uncommitted;

然后开启两个会话,每个会话中开启一个事务,模拟两个事务并发读取修改的情况。观察脏读情况。

首先,数据库中有两条数据。

会话一:

start transaction;
-- a语句
select a.id,a.username
from appointment a 
where a.id = 1;
-- b语句
update appointment a 
set username = 'nihao12'
where a.id = 1;
-- c语句
select a.id,a.username
from appointment a 
where a.id = 1;
commit;

会话二:

start transaction;
-- a语句
select a.id,a.username
from appointment a 
where a.id = 1;
commit;

首先,会话一开启事务并执行a语句,会话二开启事务并执行a语句。

结果如下:

会话一:

会话二:

接下来,会话一执行b语句,执行完后执行c语句观察结果。会话二在会话一执行完b语句后再次执行a语句。结果如下:

会话一:

会话二:

我们发现,会话二中读取到了会话一中未提交的数据。发生了脏读。

读已提交

根据读未提交中的内容将隔离级别设置为读已提交。

然后开启两个会话,每个会话中开启一个事务,模拟两个事务并发读取修改的情况。观察脏读情况。

首先,数据库中有两条数据。

会话一:

start transaction;
-- a语句
select a.id,a.username
from appointment a 
where a.id = 1;
-- b语句
update appointment a 
set username = 'nihao12'
where a.id = 1;
-- c语句
select a.id,a.username
from appointment a 
where a.id = 1;
commit;

会话二:

start transaction;
-- a语句
select a.id,a.username
from appointment a 
where a.id = 1;
commit;

首先,会话一开启事务并执行a语句,会话二开启事务并执行a语句。
结果如下:

会话一:

会话二:

接下来,会话一执行b语句,执行完后执行c语句观察结果。会话二在会话一执行完b语句后再次执行a语句。结果如下:

会话一:

会话二:

我们发现,会话二中没有读取到会话一中未提交的数据。

会话一提交数据,会话二继续执行a语句读取数据。结果如下:

会话一:

会话二:

结果表明,会话二读取到了会话一提交的数据。

可重复读

对于可重复读,和上面的步骤一样,我们从开启事务开始看起。

开启事务后,会话一执行a语句,会话二执行a语句。结果如下:

会话一:

会话二:

会话一执行b语句,然后执行c语句。会话二执行a语句。结果如下:

会话一:

会话二:

会话二无法读取到会话一未提交的数据。

会话一提交,会话二继续执行a语句。结果如下:

会话一:

会话二:

结果表明会话二无法读取到会话一提交的数据。会话二中数据可重复读取。

接下来将会话一,会话二中的代码改为下面的情况:

会话一:

start transaction;
-- a语句
select *
from appointment a 
where a.id<10;
-- b语句
insert into appointment(id,username,id_card,department,date,time) 
values(3,'nihao5',1234,'uuuu1','2010/09/08','1231');
-- c语句
select *
from appointment a
where a.id<10;
commit;

会话二:

start transaction;
-- a语句
select *
from appointment a
where a.id<10;
-- b语句
update appointment a 
set a.time = '1232'
where a.id<10;
-- c语句
select *
from appointment a
where a.id<10;
commit;

步骤会话一会话二结果1start transactionstart transaction2执行a语句执行完会话一a语句执行会话二a语句内容相同3执行b语句4执行c语句执行完会话一c语句执行会话二a语句会话一中数据有两条,会话二中数据有两条(会话二a语句为快照读,读取不到会话一修改的内容。可重复读避免了读幻读。)5commit6执行a语句会话二中数据有2条7执行b语句更新结果为3条数据(写幻读)8执行c语句查出来了2条数据

我们发现在会话二中更新后发生了幻读的现象(快照读的情况下,会发生写幻读的情况)。
为了避免写幻读的情况。可以尝试加锁。将会话二的代码改为如下所示:

start transaction;
-- a语句
select *
from appointment a
where a.id<10 for update;
-- b语句
update appointment a 
set a.time = '1231'
where a.id<10;

-- c语句
select *
from appointment a
where a.id<10;

commit;

上述代码中select … for update会加锁(具体加什么锁先不进行探讨)。执行后,会话一中的插入会被阻塞。
执行序列和结果如下表所示:

步骤会话一会话二结果
1start transactionstart transaction
2执行a语句执行完会话一a语句执行会话二a语句内容相同,会话二对内容加锁。
3执行b语句会话一插入语句被阻塞
4执行b语句更新更新两条数据
5执行c语句查出来两条数据
6commit提交,锁释放
7再次执行b语句插入成功
8执行c语句三条数据
9commit

mysql 的事务隔离级别是‌会话级设置‌,每个事务仅受自身隔离级别的约束,不影响其他事务。

注:对于以上实验,两个会话的隔离级别都是相同的。可以自己试下两个隔离级别不同的情况。

总结

到此这篇关于mysql数据库事务的acid之隔离性实验的文章就介绍到这了,更多相关mysql事务acid之隔离性内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

赞 (0)

您想发表意见!!点此发布评论

推荐阅读

从零开始学 MySQL SQL:DDL、DML、DQL 一本通

09-29

一文搞懂 MySQL CRUD:增删改查语法详解与实战

09-29

SQL里的“套娃”与“拼图”之MySQL子查询和合并查询

09-29

mysql数据库中null是什么意思详解

09-29

MySQL面试核心知识点总结与原理详细解析

09-29

MySQL表约束的实现

09-29

猜你喜欢

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论