开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第16天,点击查看活动详情
✔个人主页:Mr.Darcy8的掘金主页
🎉欢迎关注👀点赞👍收藏⭐留言📝以及交流人生哲理🎈学习心得🎁
引入
上期我们介绍了sql语言中 “事务” 的概念。这里用一句话简要回顾一下:事务即符合业务设定的最小不可分割单元,一个事务中的代码语句只有全部成功才能算成功,否则将回滚到整个事务执行之前的状态(或理解成这个事务的所有代码均未执行)
我们之前介绍过的事务ACID原则,还有印象吗?其中的“I”表示的是隔离性,任意两个事务操作到同一条记录的时候,彼此需要互不干扰。但其实这是很难做到的,除非我们一直采用单线程工作,一次运行一条语句,这样才能做到绝对的“独立”。但这显然不符合我们业务实际运用的需求,单线程工作效率太低了……
为了尽可能减少并发操作带来的数据干扰,sql标准定义了4种隔离级别,这样我们可以根据需求来有针对性地选择对应的方法,来处理并发操作带来的数据不一致问题。
我们今天先来了解第一种:Read Uncommitted
1. 脏读
一个事务读取到另一个事务更新了但是未提交的数据,我们把它称之为“脏读”(Dirty Read)
我们可以通过一个例子来直观地感受一下脏读:
假设现在我们有一个表S,其中的数据为如下状态:
mysql> select * from S;
+-----+------+
| SNo | SN |
+-----+------+
| 001 | Mike |
+-----+------+
1 row in set (0.00 sec)
为了模拟多线程操作,我们打开两个mysql客户端,并连接到同一个数据库,这个数据库中含有S表。
接下来我们按如下顺序来执行两个事务:
| 时刻 | 事务A | 事务B |
|---|---|---|
| 1 | SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; | SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; |
| 2 这时候开始事务 | BEGIN; | BEGIN; |
| 3 | UPDATE S SET SN = '小明' WHERE id = 1; | |
| 4 | SELECT * FROM S WHERE id = 1; | |
| 5 | ROLLBACK; | |
| 6 | SELECT * FROM S WHERE id = 1; | |
| 7 | COMMIT; |
先不管我们第一个时刻干了什么,大家按照“脏读”的概念,猜一猜事务B两次查询到的是什么信息?学生的名字是“小明”还是“Mike”?
是的,既然说了是脏读,那结果也很明确。第一次查询的时候事务A还没有回滚,属于“已经更新但是未提交”,此时事务B查询到的当然是“小明”了。但是第二次查询的时候事务A已经完成了回滚,所有被事务A修改的数据回到了事务A开始前的原始状态,因此事务B在这个时候查询到的自然是“Mike”了。
这便是“其他事务的中间过程修改的数据被其他事务读取”的结果
2. Read Uncommitted隔离级别
那么回过头来看第一时刻我们设置的东西:
set transaction isolation level read uncommitted;
结合本文的标题,很容易理解,这里就是把这两个事务的级别都设置成‘read uncommitted’
在这种级别下,脏读是被允许发生的。一个事务可能会读取到另一个事务更新但是未提交的数据。可以小小剧透一下,Read Uncommitted事务级别是隔离级别最低的。
新人上路,欢迎互相帮扶~Mr_darcy8的掘金主页
可以的话给咱点个赞呗💖