数据库村的旺财和小强
丢失的数据
旺财是数据库村的一个程序, 小强也是。
数据库村有个特点, 很多数据支持共享操作,多个程序可以同时读写,他们俩经常会为了读写同一个数据, 争夺的不可开交。
这一天,当旺财和小强对同一个银行账户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架构师创建,分享编程和职场的经验教训。