免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
php使用數(shù)據(jù)庫的并發(fā)問題(樂觀鎖與悲觀鎖)
在php與數(shù)據(jù)庫的交互中,如果并發(fā)量大,并且都去進行數(shù)據(jù)庫的修改的話,就有一個問題需要注意.數(shù)據(jù)的鎖問題.就會牽扯數(shù)據(jù)庫的事務(wù)跟隔離機制

數(shù)據(jù)庫事務(wù)依照不同的事務(wù)隔離級別來保證事務(wù)的ACID特性,也就是說事務(wù)不是一開啟就能解決所有并發(fā)問題。通常情況下,這里的并發(fā)操作可能帶來四種問題:
  • 更新丟失:一個事務(wù)的更新覆蓋了另一個事務(wù)的更新,這里出現(xiàn)的就是丟失更新的問題。
  • 臟讀:一個事務(wù)讀取了另一個事務(wù)未提交的數(shù)據(jù)。
  • 不可重復(fù)讀:一個事務(wù)兩次讀取同一個數(shù)據(jù),兩次讀取的數(shù)據(jù)不一致。
  • 幻象讀:一個事務(wù)兩次讀取一個范圍的記錄,兩次讀取的記錄數(shù)不一致。


通常數(shù)據(jù)庫有四種不同的事務(wù)隔離級別:
隔離級別臟讀不可重復(fù)讀幻讀
Read uncommitted
Read committed×
Repeatable read××
Serializable×××

大多數(shù)數(shù)據(jù)庫的默認(rèn)的事務(wù)隔離級別是提交讀(Read committed),而MySQL的事務(wù)隔離級別是重復(fù)讀(Repeatable read)。對于丟失更新,只有在序列化(Serializable)級別才可得到徹底解決。不過對于高性能系統(tǒng)而言,使用序列化級別的事務(wù)隔離,可能引起死鎖或者性能的急劇下降。因此使用悲觀鎖和樂觀鎖十分必要。 并發(fā)系統(tǒng)中,悲觀鎖(Pessimistic Locking)和樂觀鎖(Optimistic Locking)是兩種常用的鎖:
  • 悲觀鎖認(rèn)為,別人訪問正在改變的數(shù)據(jù)的概率是很高的,因此從數(shù)據(jù)開始更改時就將數(shù)據(jù)鎖住,直到更改完成才釋放。悲觀鎖通常由數(shù)據(jù)庫實現(xiàn)(使用SELECT...FOR UPDATE語句)。
  • 樂觀鎖認(rèn)為,別人訪問正在改變的數(shù)據(jù)的概率是很低的,因此直到修改完成準(zhǔn)備提交所做的的修改到數(shù)據(jù)庫的時候才會將數(shù)據(jù)鎖住,完成更改后釋放


***
以mysql為例子:
myisam存儲引擎使用表縮
innodb使用行鎖(明確指定了主鍵的情況下,否則也是表鎖)與表鎖

一般的做法是:
1 開啟事務(wù)
2 進行數(shù)據(jù)更改
3 回滾或者提交

在具體的業(yè)務(wù)邏輯中,由于隔離機制的不同,導(dǎo)致結(jié)果的不同.
樂觀鎖與悲觀鎖使用的也比較多.

***有這么一張表
  1. mysql> select * from counter;
  2. +----+-----+
  3. | id | num |
  4. +----+-----+
  5. |  1 |   0 |
  6. +----+-----+
  7. 1 row in set (0.00 sec)
復(fù)制代碼



悲觀鎖的例子:
  1. <?php
  2. function dummy_business() {
  3.         $conn = mysqli_connect('127.0.0.1', 'public', 'public') or die(mysqli_error());
  4.         mysqli_select_db($conn, 'test');
  5.         for ($i = 0; $i < 10000; $i++) {
  6.                 mysqli_query($conn, 'BEGIN');
  7.                 $rs = mysqli_query($conn, 'SELECT num FROM counter WHERE id = 1 FOR UPDATE');
  8.                 if($rs == false || mysqli_errno($conn)) {
  9.                         // 回滾事務(wù)
  10.                         mysqli_query($conn, 'ROLLBACK');
  11.                         // 重新執(zhí)行本次操作
  12.                         $i--;
  13.                         continue;
  14.                 }
  15.                 mysqli_free_result($rs);
  16.                 $row = mysqli_fetch_array($rs);
  17.                 $num = $row[0];
  18.                 mysqli_query($conn, 'UPDATE counter SET num = '.$num.' + 1 WHERE id = 1');
  19.                 if(mysqli_errno($conn)) {
  20.                         mysqli_query($conn, 'ROLLBACK');
  21.                 } else {
  22.                         mysqli_query($conn, 'COMMIT');
  23.                 }
  24.         }
  25.         mysqli_close($conn);
  26. }
  27.         
  28. for ($i = 0; $i < 10; $i++) {
  29.         $pid = pcntl_fork();
  30.         
  31.         if($pid == -1) {
  32.                 die('can not fork.');
  33.         } elseif (!$pid) {
  34.                 dummy_business();
  35.                 echo 'quit'.$i.PHP_EOL;
  36.                 break;
  37.         }
  38. }
  39. ?>
復(fù)制代碼
由于悲觀鎖在開始讀取時即開始鎖定,因此在并發(fā)訪問較大的情況下性能會變差。對MySQL Inodb來說,通過指定明確主鍵方式查找數(shù)據(jù)會單行鎖定,而查詢范圍操作或者非主鍵操作將會鎖表。
接下來,我們看一下如何使用樂觀鎖解決這個問題,首先我們?yōu)閏ounter表增加一列字段:
  1. mysql> select * from counter;
  2. +----+------+---------+
  3. | id | num  | version |
  4. +----+------+---------+
  5. |  1 | 1000 |    1000 |
  6. +----+------+---------+
  7. 1 row in set (0.01 sec)
復(fù)制代碼
實現(xiàn)方式:
  1. <?php
  2. function dummy_business() {
  3.         $conn = mysqli_connect('127.0.0.1', 'public', 'public') or die(mysqli_error());
  4.         mysqli_select_db($conn, 'test');
  5.         for ($i = 0; $i < 10000; $i++) {
  6.                 mysqli_query($conn, 'BEGIN');
  7.                 $rs = mysqli_query($conn, 'SELECT num, version FROM counter WHERE id = 1');
  8.                 mysqli_free_result($rs);
  9.                 $row = mysqli_fetch_array($rs);
  10.                 $num = $row[0];
  11.                 $version = $row[1];
  12.                 mysqli_query($conn, 'UPDATE counter SET num = '.$num.' + 1, version = version + 1 WHERE id = 1 AND version = '.$version);
  13.                 $affectRow = mysqli_affected_rows($conn);
  14.                 if($affectRow == 0 || mysqli_errno($conn)) {
  15.                         // 回滾事務(wù)重新提交
  16.                         mysqli_query($conn, 'ROLLBACK');
  17.                         $i--;
  18.                         continue;
  19.                 } else {
  20.                         mysqli_query($conn, 'COMMIT');
  21.                 }
  22.         }
  23.         mysqli_close($conn);
  24. }
  25.         
  26. for ($i = 0; $i < 10; $i++) {
  27.         $pid = pcntl_fork();
  28.         
  29.         if($pid == -1) {
  30.                 die('can not fork.');
  31.         } elseif (!$pid) {
  32.                 dummy_business();
  33.                 echo 'quit'.$i.PHP_EOL;
  34.                 break;
  35.         }
  36. }
  37. ?>
復(fù)制代碼
由于樂觀鎖最終執(zhí)行的方式相當(dāng)于原子化UPDATE,因此在性能上要比悲觀鎖好很多
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
php分頁代碼簡單實現(xiàn)
PHP中如何連接數(shù)據(jù)庫
《PHP+MySQL動態(tài)網(wǎng)站開發(fā)實例教程》第8章 PHP操作MySQL數(shù)據(jù)庫
怎么把PHP中復(fù)選框選中的多個值寫入到數(shù)據(jù)庫中
myssqli和mysql的函數(shù)
PHP+MySQL打造XXX管理系統(tǒng)
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服