数据库 - Mysql事务隔离级别与乐观锁的问题
黄舟
黄舟 2017-04-17 11:32:14
0
2
443

问题一:
当事务隔离级别设置为可重复读的时候,将所有select过的行都加了读锁,并且记录了版本号,当update 的时候们如果发现版本号变了,则事务失败回滚。不知道我这样理解是否正确?

问题二:
如果上面的理解正确,那是否innodb的可重复读这个隔离级别已经帮我们实现了乐观锁,所以并不需要手动通过版本或者时间戳来实现乐观锁,或者使用 悲观锁了?

问题三:
悲观锁 select ... for update 是增加了一个写锁? 所以所有的读写都会被block住?

问题四:
假设有事务A,先select 然后 update,事务B同样也是先select 然后再update
如果事务隔离级别为可重复读,事务A,B先后select加上了读锁,那么会不会因此而后面的update操作会互相block住,导致死锁?

问题一和问题四好像是矛盾的,因为如果问题四成立,事务会block住,也不会修改成功导致版本号不一致导致 回滚了。

黄舟
黄舟

人生最曼妙的风景,竟是内心的淡定与从容!

全部回覆(2)
大家讲道理

問題一:

可重複讀取(REPEATABLE READ)時,普通的SELECT 並沒有加讀鎖定(話說innodb 有讀鎖這種概念麼?),而是由mysql 快取了SELECT 的結果集,保證在這個事務裡同樣的SELECT 語句得到的結果始終一致。所以也不存在 UPDATE 的時候版本號錯誤的問題,也不會因此回滾。

可以參考:http://dev.mysql.com/doc/refman/5.6/en/innodb-consistent-read.html

問題二:

對於可重複讀取層級的事務,因為你在事務中,只要不COMMIT 任何修改都不會發生,也讀不到別人更新的數據,所以你既無法加樂觀鎖,也無法在COMMIT 前判斷別人是否已經更新了數據,這使得你無論如何都實現不了樂觀鎖。

只有用 READ COMMITTED 才能實現你希望的樂觀鎖。

問題三:

FOR UPDATE 是鎖住所有選出來的記錄,是一個寫鎖,所有的寫都會被 block,普通的 SELECT 不會被 block。

問題四:

因為沒有所謂的讀鎖存在,所以沒有你想的這個問題存在。

伊谢尔伦

這個問題有點複雜,根據事務隔離的定義,可重複讀取是需要上讀鎖的:
wiki中文說明
wiki英文說明
也就是保證讀取的內容不會改變。

但根據mysql的文檔,innodb的實現機制是在讀取的時候,建立快照,以保證在單一事務內,讀取的內容不會改變:mysql文檔

那麼就是產生了一些微妙的差異。 。 。雖然對結果來說沒差=。 =
問題一二如同@Huan Du所說,沒讀鎖所以不會失敗,需要自己實現鎖
問題四,不會有死鎖

熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!