php原子操作,檔案鎖flock,資料庫事務
php沒有繼承posix標準支援的unix鎖,只封裝了乙個linux系統呼叫flock(訊號量也能做成鎖),按理也是可以使用鎖機制的,雖然效率低一點。
php指令碼是執行在fastcgi容器中,而fastcgi是多程序的,所以如果php程式訪問了臨界資源,勢必造成程式結果的不正確性。
估計還要考慮下fastcgi容器的問題
------------------------------------
問題描述:黑客用的工具刷我們的後台
取消訂單時會有退款,黑客併發取消訂單,導致多次退款
如果請求乙個乙個來,哪怕間隔100毫秒,也是沒有問題的
乙個php處理過程是: 讀退款標誌,發現沒退款, 退款,然後設定已退款標誌
問題是多個請求同時到了,讀出來的退款標誌都是未退款,所以多個請求都退款了
同乙個php檔案,被同時請求多次,是同一時刻
用php檔案鎖flock 我們試了不行,還是用c++佇列
用c++監聽了乙個埠,直接接收http包,然後返回http格式的包,php程式中用curl訪問我這個c程式.
相當於遠端呼叫了,可以部署到其他伺服器做分布式了
很多時候,我們並沒有考慮我們php**的並行能力,尤其是在我們的php**對某個資源可讀可寫的時候。但這並不是說php的所有操作就都是原子的,事務的,可並行的。由於php指令碼是執行在fastcgi容器中,而fastcgi是多程序的,所以如果php程式訪問了臨界資源,勢必造成程式結果的不正確性。
解決問題的辦法是使用鎖機制。php沒有繼承posix標準支援的unix鎖:比如記錄鎖fcntl,執行緒鎖等,而只封裝了乙個linux系統呼叫flock(訊號量也能做成鎖),flock形式為flock($fp,$type),其中$fp為檔案控制代碼,而$type為:
/* 當乙個檔案的開啟方式是可讀可寫的,通常需要向檔案加入鎖機制 */
1. lock_sh 共享鎖:
通常為程序向檔案請求讀操作時需加共享鎖。共享鎖可支援任意個程序間的讀操作,如果寫乙個加了共享鎖的檔案則程序阻塞進入sleep狀態值到共享鎖解鎖
2. lock_ex 獨佔鎖:
通常為程序向檔案的寫操作加獨佔鎖,一旦檔案加上了該鎖,則其他任意程序訪問該檔案時都會阻塞,直到解鎖為止。
3. lock_un 解鎖:
為加鎖的檔案控制代碼解鎖
這樣的加鎖方式必然可以保證加鎖程式塊的原子性,但同時也犧牲了程式的效率,因此,我們實際的程式中應該在程式的加鎖和解鎖**間嵌入盡量少的程式邏輯(尤其是獨佔鎖),保證程式盡快解鎖。
最後,附上加上鎖機制以後的程式:
<?php
$usrinfo = isset($_get["usrinfo"])?$_get["usrinfo"]:exit(1);
$stinfo = isset($_get["stinfo"])?$_get["stinfo"]:exit(1);
echo $stinfo;
$pid = posix_getpid();
$fp = fopen(「usrinfo.txt」,」a+」);
$num = rand(0,100000);
flock($fp,lock_ex);
fwrite($fp,」user:」.$usrinfo.」 stinfo:」.$stinfo.」–」.$pid.」–」.$num.」\n」);
fwrite($fp,」talking 1 — pid:$pid and num:$num\n」);
flock($fp,lock_un);
fclose($fp);
普通情況執行該程式,產生正確的結果。
用什麼方法可以在業務批量操作時保證原子性呢?
例如:刪除多條文章,但在中間有一條已經被刪除了,假設這裡會出現錯誤,那如何讓整個操作回滾,並定位錯誤資訊呢?
資料庫的事務保證原子性但不能定位錯誤資訊,但遇到無法使用事務的場景,應該怎麼做呢?
----------------------------------------
利用資料庫的事務來做是最合理的,錯誤資訊可以記錄啊,有操作失敗丟擲錯誤。
應用邏輯來保證,就是每操作一次做下記錄,成功失敗都做下記錄。中間出錯,可以把成功的回滾。一般我們刪除是假刪除,所以很容易。如果真刪除,記錄時要記錄完整資訊。
****************************************
php用檔案鎖模擬程序鎖,實現原子操作
用php實現原子操作,而php本身並沒有提供程序鎖機制,用php檔案鎖機制,通過檔案鎖模擬程序鎖實現原子操作。
原子操作的**之前,使用排他鎖開啟某個檔案,**如下:
$fp = fopen( lock_file_path, "r" );
if (!$fp)
flock ( $fp, lock_ex );
原子操作的**之後,對該檔案解鎖,並關閉檔案,**如下:
flock ( $fp, lock_un );
fclose ( $fp );
整體偽**為:
define("lock_file_path", "/tmp/lock");
if( !file_exists(lock_file_path) )
$fp = fopen( lock_file_path, "r" );
if (!$fp)
flock ( $fp, lock_ex );
//此處新增原子操作**
flock ( $fp, lock_un );
fclose ( $fp );
以上便可實現php原子操作,避免衝突。
php原子操作與mysql原子操作
原子操作常用的方法就是通過資料回滾來實現,用 php 來實現資料庫回滾操作相當簡單:
1, 建立資料庫連線
2, mysql_query('begin'); 開啟事務
3, $sql = "...";
mysql_query($sql); 做相應的資料庫操作
4, 判斷回滾條件:
if(mysql_errno)
5,可以重複上述步驟 3 及步驟 4 的操作, 開始的過程(中間可以加入其他操作,不侷限於資料庫更新,但是注意,最好不要讓乙個事務時間過長,因為它鎖定所有你用到的表,會影響其他程式使用)
你也可以在幾條正確的sql更新語句後故意寫一句錯誤的,看看是否回滾了。
6, 結束回滾操作
mysql_query('commit'); 能夠到這裡,代表上述資料庫操作都沒有錯,正式提交執行
這就是用 php 實現原子操作的整個過程,需要特別注意的是建立支援資料回滾操作的表結構,
另外,除 commit 外也有其它辦法可以結束回滾操作。
flock 函式 檔案鎖
檔案鎖是一種檔案讀寫機制,在任何特定的時間只允許乙個程序訪問乙個檔案。利用這種機制能夠使讀寫單個檔案的過程變得更安全。這裡我們使用flock 函式。flock函式說明 flock 會依引數operation所指定的方式對引數fd所指的檔案做各種鎖定或解除鎖定的動作。此函式只能鎖定整個檔案,無法鎖定檔...
php操作檔案
實現php寫入,讀取,替換檔案內容。先解釋一下,主要用到 fopen 檔名.副檔名 操作方式 fwrite 讀取的檔案,寫入的檔案 fclose 開啟的物件變數 寫入檔案 w表示以寫入的方式開啟檔案,如果檔案不存在,系統會自動建立 file pointer fopen sb.log a fwrite...
linux使用flock檔案鎖
使用linux flock 檔案鎖實現任務鎖定,解決衝突 格式 flock sxun w fd flock sxon w file c command flock help flock util linux ng 2.17.2 usage flock sxun w fd flock sxon w f...