摘要:樂(lè)觀鎖樂(lè)觀鎖實(shí)際上是一種邏輯思想,并不是數(shù)據(jù)庫(kù)的特性。悲觀鎖利用了存儲(chǔ)引擎的支持行鎖的特性。建議在用戶并發(fā)量不大的應(yīng)用場(chǎng)景下,采用樂(lè)觀鎖的方式。在對(duì)數(shù)據(jù)一致性要求很高的情況下,可以犧牲一下性能,采用悲觀鎖。
MySQL5.5 版本之后默認(rèn)采用innoDb 數(shù)據(jù)引擎.本文采用默認(rèn)的存儲(chǔ)引擎。樂(lè)觀鎖
樂(lè)觀鎖實(shí)際上是一種邏輯思想,并不是mysql 數(shù)據(jù)庫(kù)的特性。這個(gè)要區(qū)分清楚。 實(shí)現(xiàn)數(shù)據(jù)版本有兩種方式,第一種是使用版本號(hào),第二種是使用時(shí)間戳。
使用方式::
/** 偽代碼 number 庫(kù)存 goods_id 商品ID version 版本號(hào)默認(rèn)為0 **/ $sql="select number from goods where goods_id={$goods_id} and version= {$version} "; // 時(shí)間戳方式查詢庫(kù)存 $sql="select number from goods where goods_id={$goods_id} and time < time() "; $rs=mysqli_query($conn,$sql); $row = $rs->fetch_assoc(); if($row["number"]>0){//高并發(fā)下會(huì)導(dǎo)致超賣 if($row["number"]<$number){ return insertLog("庫(kù)存不夠",3,$username); } //庫(kù)存減少 $sql="update goods set number=number-{$number},version += 1 where goods_id={$goods_id} and number>0"; // 時(shí)間戳方式減少庫(kù)存 $sql="update goods set number=number-{$number},time = time() where goods_id={$goods_id} and number>0"; $store_rs=mysqli_query($conn,$sql); if($store_rs){ //生成訂單,返回操作成功 echo json_encode(array("code"=>0,"msg"=>"庫(kù)存減少成功","data"=>$username)); }else{ echo json_encode(array("code"=>1,"msg"=>"庫(kù)存減少失敗","data"=>$username)); } }else{ echo json_encode(array("code"=>3,"msg"=>"庫(kù)存減少失敗","data"=>$username)); }
悲觀鎖注意:使用樂(lè)觀鎖需要注意啊,將庫(kù)存字段number字段設(shè)為unsigned,當(dāng)庫(kù)存為0時(shí),因?yàn)樽侄尾荒転樨?fù)數(shù),將會(huì)返回false
悲觀鎖指的是對(duì)數(shù)據(jù)被外界(包括本系統(tǒng)當(dāng)前的其他事務(wù),以及來(lái)自外部系統(tǒng)的事務(wù)處理)修改持保守態(tài)度,因此,在整個(gè)數(shù)據(jù)處理過(guò)程中,將數(shù)據(jù)處于鎖定狀態(tài)。悲觀鎖的實(shí)現(xiàn),往往依靠數(shù)據(jù)庫(kù)提供的鎖機(jī)制(也只有數(shù)據(jù)庫(kù)層提供的鎖機(jī)制才能真正保證數(shù)據(jù)訪問(wèn)的排他性,否則,即使在本系統(tǒng)中實(shí)現(xiàn)了加鎖機(jī)制,也無(wú)法保證外部系統(tǒng)不會(huì)修改數(shù)據(jù))。悲觀鎖利用了MySQL innoDB 存儲(chǔ)引擎的支持行鎖的特性。一行一行操作數(shù)據(jù).
使用方式:
// 使用悲觀鎖鎖住當(dāng)前行 $sql="select number from goods where goods_id={$goods_id} for update "; // 減少庫(kù)存操作 $sql="update goods set number=number-{$number} where goods_id={$goods_id} and number>0";
注意:innoDB 行鎖是基于索引來(lái)執(zhí)行的,where 條件后必須有索引,不然走的就是全表掃描。
優(yōu)點(diǎn)與不足:
悲觀并發(fā)控制實(shí)際上是“先取鎖再訪問(wèn)”的保守策略,為數(shù)據(jù)處理的安全提供了保證。但是在效率方面,處理加鎖的機(jī)制會(huì)讓數(shù)據(jù)庫(kù)產(chǎn)生額外的開(kāi)銷,還有增加產(chǎn)生死鎖的機(jī)會(huì);另外,在只讀型事務(wù)處理中由于不會(huì)產(chǎn)生沖突,也沒(méi)必要使用鎖,這樣做只能增加系統(tǒng)負(fù)載;還有會(huì)降低了并行性,一個(gè)事務(wù)如果鎖定了某行數(shù)據(jù),其他事務(wù)就必須等待該事務(wù)處理完才可以處理那行數(shù)樂(lè)觀并發(fā)控制相信事務(wù)之間的數(shù)據(jù)競(jìng)爭(zhēng)(datarace)的概率是比較小的,因此盡可能直接做下去,直到提交的時(shí)候才去鎖定,所以不會(huì)產(chǎn)生任何鎖和死鎖。但如果直接簡(jiǎn)單這么做,還是有可能會(huì)遇到不可預(yù)期的結(jié)果,例如兩個(gè)事務(wù)都讀取了數(shù)據(jù)庫(kù)的某一行,經(jīng)過(guò)修改以后寫(xiě)回?cái)?shù)據(jù)庫(kù),這時(shí)就遇到了問(wèn)題。
建議: 在用戶并發(fā)量不大的應(yīng)用場(chǎng)景下,采用樂(lè)觀鎖的方式。在對(duì)數(shù)據(jù)一致性要求很高的情況下,可以犧牲一下性能,采用悲觀鎖。這個(gè)兩種方式的前提是采用MySQL的解決方案。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/31279.html
摘要:并發(fā)同步控制遇到并發(fā)時(shí),我們避免不了要談并發(fā)控制。它會(huì)阻塞其它的線程執(zhí)行,如果當(dāng)前線程一直持有的監(jiān)控鎖,就會(huì)把其它線程一直阻塞下去。如果此時(shí)線程和線程同時(shí)進(jìn)入方法,用一段語(yǔ)言描述方法的執(zhí)行過(guò)程,可能是這樣子。 并發(fā)同步控制 遇到并發(fā)時(shí),我們避免不了要談并發(fā)控制。在Java語(yǔ)言中,我們談并發(fā)時(shí),要談到Object的監(jiān)控鎖。在MySQL的數(shù)據(jù)庫(kù)并發(fā)中,我們也要談到mysql的鎖機(jī)制。 這樣...
閱讀 816·2021-11-12 10:36
閱讀 3409·2021-09-08 10:44
閱讀 2767·2019-08-30 11:08
閱讀 1429·2019-08-29 16:12
閱讀 2695·2019-08-29 12:24
閱讀 921·2019-08-26 10:14
閱讀 709·2019-08-23 18:32
閱讀 1202·2019-08-23 17:52