查看原文
其他

数据库村的旺财和小强

2016-12-07 刘欣 码农翻身

丢失的数据

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


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


这一天,当旺财和小强对同一个银行账户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 不屑一顾的说: “这都嫌麻烦了, 你们还没遇到死锁呢....”


你看到的只是冰山一角, 更多精彩文章,尽在“码农翻身” 微信公众号, 回复消息"m"或"目录" 查看更多文章


有心得想和大家分享? 欢迎投稿 ! 我的联系方式:微信:liuxinlehan  QQ: 3340792577


公众号:码农翻身

“码农翻身”公众号由工作15年的前IBM架构师创建,分享编程和职场的经验教训。



您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存