laravel mysql 锁表_Laravel中MySQL的乐观锁与悲观锁
MySQL/InnoDB的加鎖,是一個(gè)老生常談的話題。在數(shù)據(jù)庫高并發(fā)請(qǐng)求下,如何兼顧數(shù)據(jù)完整性與用戶體驗(yàn)的敏捷性是一代又一代程序員一直在思考的問題。
樂觀鎖
樂觀鎖之所以叫樂觀,是因?yàn)檫@個(gè)模式不會(huì)對(duì)數(shù)據(jù)加鎖。而是對(duì)數(shù)據(jù)操作保持一種樂觀的心態(tài),認(rèn)為不會(huì)產(chǎn)生并發(fā)操作問題(即不會(huì)有其他線程同時(shí)對(duì)數(shù)據(jù)進(jìn)行修改)。樂觀鎖查詢數(shù)據(jù)時(shí)直接進(jìn)行查詢,更新時(shí)會(huì)判斷其他線程有沒有對(duì)數(shù)據(jù)進(jìn)行修改,如果沒有則進(jìn)行更新,反之則拒絕更新。
樂觀鎖最常用數(shù)據(jù)版本(Version)的記錄機(jī)制實(shí)現(xiàn)。即為數(shù)據(jù)增加一個(gè)版本標(biāo)識(shí),一般是通過為數(shù)據(jù)庫表增加一個(gè)數(shù)字類型的 “version” 字段來實(shí)現(xiàn)。當(dāng)讀取數(shù)據(jù)時(shí),將version字段的值一同讀出,數(shù)據(jù)每更新一次,對(duì)此version值加1。當(dāng)我們提交更新的時(shí)候,判斷數(shù)據(jù)庫表對(duì)應(yīng)記錄的當(dāng)前版本信息與第一次取出來的version值進(jìn)行比對(duì),如果數(shù)據(jù)庫表當(dāng)前版本號(hào)與第一次取出來的version值相等,則予以更新,否則認(rèn)為是過期數(shù)據(jù)。
示例:
1、數(shù)據(jù)庫表三個(gè)字段,分別是id、value、versionselect id,value,version from TABLE where id = #{id}
2、每次更新表中的value字段時(shí),為了防止發(fā)生沖突,需要這樣操作:update TABLE
set value=2,version=version+1
where id=#{id} and version=#{version}
在larave中,我們可以在數(shù)據(jù)庫維護(hù)一個(gè)lock_version字段,每次更新操作時(shí),校驗(yàn)lock_version,并在更新完成后增加lock_version的值。
悲觀鎖
悲觀鎖就比較狠了,悲觀鎖對(duì)數(shù)據(jù)做“有罪推定”。即在操作數(shù)據(jù)時(shí),默認(rèn)此操作會(huì)出現(xiàn)數(shù)據(jù)沖突,所以在進(jìn)行每次操作時(shí)都要加鎖才能進(jìn)行對(duì)相同數(shù)據(jù)的操作。一旦加鎖,不同線程同時(shí)執(zhí)行時(shí),只能有一個(gè)線程執(zhí)行,其他的線程在入口處等待,直到鎖被釋放。
悲觀鎖可以由數(shù)據(jù)庫語句實(shí)現(xiàn),分為共享鎖和排它鎖。
共享鎖 (lock in share mode)
共享鎖又稱讀鎖 (read lock),是讀取操作創(chuàng)建的鎖。其他用戶可以并發(fā)讀取數(shù)據(jù),但任何事務(wù)都不能對(duì)數(shù)據(jù)進(jìn)行修改(獲取數(shù)據(jù)上的排他鎖),直到已釋放所有共享鎖。如果事務(wù)對(duì)讀鎖進(jìn)行修改操作,很可能會(huì)造成死鎖。
在Laravel中,我們?cè)跇?gòu)造查詢時(shí),可以使用 sharedLock 方法為運(yùn)行語句增加一把”共享鎖“。DB::table('users')->where('votes', '>', 100)->sharedLock()->get();
上面這個(gè)查詢等價(jià)于下面這條 SQL 語句:select * from `users` where `votes` > '100' lock in share mode
注意
在查詢語句后面增加 LOCK IN SHARE MODE 后,Mysql會(huì)對(duì)查詢結(jié)果中的每行都加一個(gè)共享(讀)鎖,當(dāng)沒有其他線程對(duì)查詢結(jié)果集中的任何一行使用排他鎖時(shí),可以成功申請(qǐng)共享鎖,否則會(huì)被阻塞。 其他線程也可以讀取使用了共享鎖的表,而且這些線程讀取的是同一個(gè)版本的數(shù)據(jù)。
加上共享鎖后,對(duì)于update,insert,delete語句會(huì)自動(dòng)加排它鎖。
排它鎖 (for update)
排他鎖又稱寫鎖(exclusive lock or writer lock)。若某個(gè)事務(wù)對(duì)某一行加上了排他鎖,只能這個(gè)事務(wù)對(duì)其進(jìn)行讀寫,在此事務(wù)結(jié)束之前,其他事務(wù)不能對(duì)其進(jìn)行加任何鎖,其他進(jìn)程可以讀取,不能進(jìn)行寫操作,需等待其釋放。排它鎖會(huì)阻塞所有的排它鎖和共享鎖。
在Laravel中,我們?cè)跇?gòu)造查詢時(shí),可以使用 lockForUpdate 方法為運(yùn)行語句增加一把“排它鎖”,避免選擇行被其它共享鎖修改或刪除:DB::table('users')->where('votes', '>', 100)->lockForUpdate()->get();
上面這個(gè)查詢等價(jià)于下面這條 SQL 語句:select * from `users` where `votes` > '100' for update
注意
for update 與 lock in share mode 都是用于確保被選中的記錄值不能被其它事務(wù)更新(上鎖),兩者的區(qū)別在于 lock in share mode 不會(huì)阻塞其它事務(wù)讀取被鎖定行記錄的值,而 for update 會(huì)阻塞其他鎖定性讀對(duì)鎖定行的讀取(非鎖定性讀仍然可以讀取這些記錄,lock in share mode 和 for update 都是鎖定性讀)。
總結(jié)
樂觀鎖適用于讀多寫少的情況,即沖突真的很少發(fā)生的時(shí)候,這樣可以省去了鎖的開銷,加大了系統(tǒng)的整個(gè)吞吐量。
但如果經(jīng)常產(chǎn)生沖突,還是使用悲觀鎖更穩(wěn)定、可靠一些。
參考鏈接
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的laravel mysql 锁表_Laravel中MySQL的乐观锁与悲观锁的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: centos lnmp源码安装mysql
- 下一篇: mysql 超长记录_谁记录了mysql