php並發解決方案


事務不能解決並發,只能保證在一個事務內所有操作的一致性

 常見的並發處理如下:

1.悲觀鎖

為什么叫悲觀鎖?

默認每次的執行都會發生並發

表必須是innodb類型,必須在事務中執行,加上for update 查詢的表id=10數據是,這條數據就被鎖定了,第一個人獲得鎖,后面的人只能等待第一個人完成事務提交后才能獲得鎖進行操作  

$this->db->begin(); // 開啟事務
try{
  $info = $this->db->findOne("select * from table where id=1 FOR UPDATE ");
  sleep(5);
  $this->db->commit() // 只有提交后后面的請求才可以執行
} catch (\Exception $e) {
    $this->db->rollback()
}

 

2.樂觀鎖

為什么叫樂觀鎖?

默認每次的執行都不會發生並發,只有到真正執行變更的時候檢測並發

原理是利用mysql update 原子性,也就是不論多少次並發,mysql update 只會一條一條的更新

例:

$this->db->begin(); //開啟事務
try{
    $info = $this->db->findOne("select id,name,version from table where id=1");
    sleep(5);
    // 其他邏輯
    $version = $info['version'] + 1;
    // 主要防止並發在這里
    $this->db->excute("update set name='123', version=$version where version=$info['version'] and id=1 ");
    $this->db->commit()
} catch (\Exception $e) {
    $this->db->rollback()
}

 

3.redis鎖

// 單個用戶重復提交 場景
$hasLock = $this->redis->set($key . '用戶唯一標識', 1, 'nx', 'ex', $expire);
if (!$hasLock) { // 沒有獲得鎖
    throw new Exception('排隊中請稍后...');
}
// 並發場景
$hasLock = $this->redis->set($key, 1, 'nx', 'ex', $expire);
if (!$hasLock) { // 沒有獲得鎖
    throw new Exception(''排隊中請稍后...');
}
sleep(5);
// 處理完業務 解鎖
$this->redis->del($key);

 

4.redis隊列

以上方法都不是真正意義上的並發,都是強制用戶排隊一個一個的來,而redis 隊列可以實現真正的並發

根據具體業務的提前使用$this->redis->lpush(); 將需要並發的紅包或者商品lpush入列,並發的時候lpop出列,因為lpop是原子性操作所以不會發生超賣或超領情況

 

5.其他

redis lua腳本、redis事務、中間件 等

 

 

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM