开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第17天,点击查看活动详情
✔个人主页:Mr.Darcy8的掘金主页
🎉欢迎关注👀点赞👍收藏⭐留言📝以及交流人生哲理🎈学习心得🎁
引入
上期我们介绍了一个最低的隔离级别——Read Uncommitted。其允许了脏读的发生:
即并行事务中,一个事务可以读取另一个事务更新但未提交的数据
本期我们在了解read uncommitted的基础上,了解一下他的“孪生兄弟”——Read Committed
1.不可重复读
和之前一样,我们先来了解另外一个东西:不可重复读(Non Repeatable Read)
其大意是,一个多次读取同一数据的事务,如果在其读取过程中有其他并行事务修改了该数据,则其读取的同一数据会不一致。
我知道大家对晦涩的解释没有兴趣,其实俺也一样。我们来举个例子:
事务A一直在读取数据库某表中“姓名”为“小明”的“性别”,一般情况下得到的结果一直是“男”,但突然有个事务B(是并行事务,和A一起运作),把“小明”的“性别”改成“女”了。这可以吗?当然可以,因为没人能确定小明到底是男是女。但是问题在于,事务A的隔离级别如果是Read Committed,那它就会把这个修改结果读过去,此时在事务A返回的结果中“小明”既有“男”,也有“女”。这就是个问题了,数据不一致了该信哪个?总不可能既是男的又是女的orz
所以为了避免这个问题,在Read Committed隔离级别下,我们不能进行多次读取的操作(就像错误的名字“不可重复读”一样),读一次数据就必须完成所需要的业务了,再读可能就会出错。
2.数据库案例
举了形象的例子,我们接下来就看一看实际sql语言命令下的“不可重复读”案例。
假设我们用两个终端连接了同一个mysql数据库,按照如下的时刻进行两个终端的事务:
| 时刻 | 事务A | 事务B |
|---|---|---|
| 1 | SET TRANSACTION ISOLATION LEVEL READ COMMITTED; | SET TRANSACTION ISOLATION LEVEL READ COMMITTED; |
| 2 | BEGIN; | BEGIN; |
| 3 | SELECT * FROM s WHERE name = "小明"; #此时返回"男" | |
| 4 | UPDATE s SET gender = "女" WHERE name = "小明"; | |
| 5 | COMMIT; | |
| 6 | SELECT * FROM s WHERE name = "小明"; #此时返回"女" | |
| 7 | COMMIT; |
我已经将运行结果也打在了表格里。第3时刻事务B读取的是男,第6时刻却读取出了女,出现数据不一致的问题。
所以在设置Read Committed隔离级别的时候,我们一定要注意,是不是该事务所读取的数据都能一次性读取完,不能出现重复读取同一个数据的情况。如果非得重复读取同一个数据,还请换个高一点的隔离级别,牺牲一下计算机的性能和效率,换来业务的不出错吧~
新人上路,欢迎互相帮扶~Mr_darcy8的掘金主页
可以的话给咱点个赞呗💖