台灣最大程式設計社群網站
線上人數
952
 
會員總數:246135
討論主題:189716
歡迎您免費加入會員
討論區列表 >> PHP >> php mysql 交易問題
[]  
[我要回覆]
1
回應主題 加入我的關注話題 檢舉此篇討論 將提問者加入個人黑名單
php mysql 交易問題
價值 : 30 QP  點閱數:2365 回應數:6
樓主

漢堡
初學者
10 26
496 60
發送站內信

這是個老問題了,但是我爬了文,買書看。
卻越來越無法弄懂到底PHP要怎做?
我有個欄位,在大量網頁同時存取下。怎樣才能做到,
不會被讀到錯誤值,重覆存取。(我一時忘了那個專有名詞怎講)
舉例來講,A、B同時讀取同一欄位,A取得10並修改成5,
但B是剛剛一起讀的,所以是也是讀到10並做-3,
這時B在修改欄位會是(10-3)而不是(5-3)才對。
PHP程式要怎樣寫才能避免掉這樣的錯誤??
我記得是要使用mysql的 交易 (Transaction)對吧。
以下是我的簡單測試語法的其中一段,能否幫我看看哪裡寫錯了 感謝

<?php
mysql_query('SET AUTOCOMMIT=0');
mysql_query('BEGIN WORK');

$ids="select `q` from `test`";
$da=mysql_query($ids);
$dr=mysql_fetch_row($da);
$dr[0]--;

if($dr[0]>='0'){
$ids="update `hotel`.`test` set `q`='$dr[0]'";
mysql_query($ids);
echo $ids."<br />";
}
mysql_query('COMMIT WORK');
?>

本篇文章發表於2012-12-04 17:18
1樓
最有價值解答

浩瀚星空
捐贈 VP 給 浩瀚星空 檢舉此回應
這是很典形的問題,也就是所謂的同時運行發生的問題。

很多人常做的是事先取得數值並+-後寫入。其實這樣的做法是錯的。

一般來說,碰上這種需要加減,且可能同時多人操作的。最好的做法是用UPDATE時上做+-。
也就是不要預先取值出來。(當然,如果程式上需要取值出來顯示就另當別論)

依你上面的程式我重新修改如下,你去意會一下.
另外你Q值最好還是用數字型態。

本篇文章回覆於2012-12-05 09:39
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
2樓
作者回應

漢堡
檢舉此回應
這位大大的你提供的解法,我改寫我程式如下
$ids="update `hotel`.`test` set `q`=`q`-1 where `q`>0";
$da=mysql_query($ids);

global $y;
if(mysql_affected_rows()=='1'){
$y++;
}
我用迴圈開10幾個頁面模擬搶庫存,並結算取得$y值,確實是設定的100。
不過雖然是如預期的成功了。只是想說這方法似乎,無用到mysql的交易這個功能。
至今完全無法了解,怎在PHP上實做mysql的交易。
如(BEGIN)、(COMMIT)、(ROLLBACK)、(LOCK)怎在PHP上實作?
還是說業界這邊比較少會去用那些功能呢????希望能有大大能幫我解惑(能有實例更好),
@_@mysql交易這邊不管是爬書、爬文,都是寫的很亂。非常感謝大大們。
本篇文章回覆於2012-12-05 11:13
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
3樓
回應

浩瀚星空
捐贈 VP 給 浩瀚星空 檢舉此回應
這埵釩D常好用的手冊提供埵bPHP和何操作MYSQL的一些用法。
http://php.net/manual/en/book.mysql.php

內有針對各函數的用處用法及範例。
你只要能全部玩過一次。就大至上能了解如何的操作。
剩下來的就是基本的邏輯觀念及經驗了。

多練習幾次,因為有些是屬於MYSQL的應用術而非PHP。PHP也只是做「操作」
相關的MYSQL用法,在MYSQL版的版主很強。有問題你也可以去請教他。
本篇文章回覆於2012-12-05 17:27
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
4樓
作者回應

漢堡
檢舉此回應
我會努力精進mysql能力感謝^^
本篇文章回覆於2012-12-06 10:19
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
5樓
回應

Solty
檢舉此回應
很多人常做的是事先取得數值並+-後寫入。其實這樣的做法是錯的。
-----------------
其實這是看應用,如果是一個扣庫存的操作,先撈才是正確的,因為你總是不能讓庫存變成負的吧!?
漢堡你的問題,單靠交易無法解決,當然交易也是有必要用的,因為這必須使用列鎖(innodb lock row),而列鎖必須在交易中才會生效
本篇文章回覆於2012-12-11 10:45
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
6樓
回應

浩瀚星空
捐贈 VP 給 浩瀚星空 檢舉此回應
#Solty

你說的沒有錯,但一般這堳的是判定值。

其實兩種做法都非是一種很好的方式
因為直接UPDATE來處理,的確也會碰上這類的問題。

一般處理的方式,我還是會用UPDATE的扣除方式。但會事先取值來判斷。
要不然就是再加上WHERE的不為0條件。再去判斷是否有更新的筆數。

當然,鎖表也是一種做法。只是鎖表也會產生一些問題存在。
一般就是看其運做來決定最適合的方式。

但利用取出的值來做直接的指定更新,是最危險的事。很容易產生虛有的庫存量或是量。
我還是會堅持使用UPDATE的+-處理。就算變成負數。至少可以馬上知道發生問題。
比那種永遠的1庫存來說,還要安全許多了。

我為何會這樣說,因為我早期就碰過了。幫客戶處理的。當時他是說會莫名的庫存不對。但查不出原因。
每一次都要再盤點一次做修正很煩。

我後來接手後就發現到這樣的問題,改掉就不會再發生庫存不對的問題了。
至於有沒有產生負數,因為他們很少讓庫存量降低到10以下,所以都沒發生過。
本篇文章回覆於2012-12-19 11:19
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
   
1

回覆
如要回應,請先登入.