返回介绍

数据库村的旺财和小强

发布于 2025-01-22 00:38:45 字数 3833 浏览 0 评论 0 收藏 0

丢失的数据

旺财是数据库村的一个程序, 小强也是。

数据库村有个特点, 很多数据支持共享操作,多个程序可以同时读写,他们俩经常会为了读写同一个数据, 争夺的不可开交。

这一天,当旺财和小强对同一个银行账户 A 进行写操作时候, 出现了这么一个错误:

看看, 本来旺财要加上的 20 元就丢掉了。

同样的事情发生的多了, 他俩给这种情况起了一个名字,叫“ 丢失修改 ”, 其实说白了就是俩人都去写一个数据, 一个人的数据把另外一个给覆盖了。

村里的 Mysql 说: “你们两个小家伙,写数据的时候连加锁都不做,肯定会出大乱子!"

旺财说:“加什么锁?”

“来来来, 我教你们一个排他锁(Exclusive Lock) , 简称 X 锁 , 旺财你要写数据了, 就把它用 X 锁锁住, 锁住后,除非你释放, 否则小强无法获得 X 锁。 这不就解决你们的问题了? ”

小强想了想, 就把上面的操作过程用 X 锁改了一下:

旺财说:“果然不错, 确实可以解决两个人同时修改导致的问题。”

脏数据

小强说:“旺财, 我们约定,写数据的时候都用 X 锁吧?”

旺财说: “这没问题, 可是 X 锁只在写数据的时候用, 我们读数据是不用加锁的, 我想起了一种情况, 你看看怎么办?”

小强在旺财执行的途中读了 A 的值, 但是旺财把对 A 的修改给回滚(Rollback) 了,这下小强尴尬了, 他读到了 脏数据

“要不我们在读取数据的时候也加个 X 锁 ? ” 小强说。

“那样太严格了, 就是读一个数据啊, 值得吗?”

“这样吧, 我们再搞一个新的锁出来, 专门用于共享数据的读取, 就叫共享锁(Share lock) ,简称 S 锁, 这个锁和之前的排他锁 X 锁有区别, 主要用于读取数据, 如果一个数据加了 X 锁, 就没法加 S 锁, 同样加了 S 锁, 就没法加 X 锁 ” 小强想出了一个点子。

“那如果我加了 S 锁, 你还能加 S 锁吗? ” 旺财问。

“应该可以吧, 咱们俩都是读数据, 互不影响啊。 还有为了防止长时间的锁住, 我们可以约定一下,不管我们要做的事情有多少, 读一个数据之前加 S 锁, 读完之后立刻释放该 S 锁 ! ”

果然,这样一来“脏数据”的问题就解决了 !

没法重复读?

旺财和小强两个程序相安无事了很久, 但是 S 锁在读完数据后立刻释放的约定, 导致出了一个新问题。

旺财在一次数据处理中, 先读取了 A 和 B 的值, 相加得到了 150 , 然后小强把 B 改成了 30

旺财再次读取 A 和 B, 发现求和以后是 130 , 刚才的不一样了!

(注: 假定旺财的处理是在一个事务当中)

旺财说: “小强, 我在读取数据的时候你不能改啊 , 要不然我这里会出现不一致, 你看刚开始是 A+B 是 150, 现在变成 130 了”

小强说: “我们之前的约定是读数据时加 S 锁, 读完立马释放, 问题就出现在这里了。”

“看来在读数据的时候, 也需要一直锁定了, 直到事务提交。”

幻觉出现

旺财和小强现在已经能灵活的使用 X 锁和 S 锁了。

他们俩总结了一下, 分为了这么几种情况:

1. 写数据时加上 X 锁,直到事务结束, 读的时候不加锁。

虽然能够避免丢失数据, 但是可以读到没有提交或者回滚的内容 (脏数据), 这其实就是数据库最低的事务隔离级别 --- Read uncommitted

2. 写数据的时候加上 X 锁, 直到事务结束, 读的时候加上 S 锁, 读完数据立刻释放。

这能避免“丢失数据”和“脏数据”, 但是会出现“不可重复读”的问题 , 这是第二级的事务隔离级别 -- Read committed

3. 写数据的时候加上 X 锁, 直到事务结束, 读数据的时候加 S 锁, 也是直到事务结束。

这能避免“丢失数据”和“脏数据”, “不可重复读”三个问题 , 这是数据库常用的隔离级别 --

Repeatable read

整个世界似乎清净了。

有一次旺财对一个“学生表”进行操作,选取了年龄是 18 岁的所有行, 用 X 锁锁住, 并且做了修改。

改完以后旺财再次选择所有年龄是 18 岁的行, 想做一个确认, 没想到有一行竟然没有修改!

这是怎么回事? 出了幻觉吗?

原来就在旺财查询并修改的的时候, 小强也对学生表进行操作, 他插入了一个新的行,其中的年龄也是 18 岁! 虽然两个人的修改都没有问题, 互不影响, 但从最终效果看, 还是出了事。

(注: 正是小强的操作, 让旺财出现了“幻读”)

旺财说: “没辙了, 我们俩非得串行执行不可, 你必须得等我执行完。 ”

这就是数据库事务隔离级别的终极大招: Serializable

最后, 为了方便记忆, 他们俩倒腾了半天, 整出了一张表, 用于记录各种情况:

(点击看大图)

两个人看着这张表, 感慨的说:“唉, 这数据库村的事务隔离级别可真是不容易啊!”

Mysql 不屑一顾的说: “这都嫌麻烦了, 你们还没遇到死锁呢....”

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文