php原子操作,檔案鎖flock,資料庫事務

2021-09-08 12:05:47 字數 3357 閱讀 5320

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...