2012-03-21 35 views
6

我正在幫助一個朋友與他們的業務基於Web的形式。我正試圖讓它準備好處理多個用戶。我已經設置它,以便在顯示記錄之前進行編輯,我用下面的代碼鎖定記錄。通過php mysql的行鎖定

$query = "START TRANSACTION;"; 
mysql_query($query); 
$query = "SELECT field FROM table WHERE ID = \"$value\" FOR UPDATE;"; 
mysql_query($query); 

(還好是被大大簡化,但是這是MySQL的精華)

它似乎並不奏效。然而,當我直接去到MySQL命令行,使用相同的用戶登錄並執行

START TRANSACTION; 
SELECT field FROM table WHERE ID = "40" FOR UPDATE; 

我可以有效地訪問記錄「40」阻塞的網頁表單並獲取超時警告。

我曾嘗試使用BEGIN而不是START TRANSACTION。我已經嘗試過首先SET AUTOCOMMIT = 0並在鎖定後啓動事務,但我似乎無法鎖定PHP代碼中的行。因爲我可以從命令行鎖定該行,所以我不認爲數據庫設置有問題。我真的很希望有一些我在閱讀時錯過的簡單的東西。僅供參考,我正在開發XAMPP 1.7.3版,其中包含Apache 2.2.14,MySQL 5.1.41和PHP 5.3.1。

在此先感謝。這是我第一次發帖,但過去我從這個網站蒐集了大量的知識。

+0

你在第二個mysql_query($ query)後做了什麼; ?如果你的php腳本退出了,那麼鎖定版本 – PasteBT 2012-03-21 23:18:55

回答

0

使用PDO這(和所有數據庫操作):

$value = 40; 

try { 
    $dbh = new PDO("mysql:host=localhost;dbname=dbname", 'username', 'password'); 
} catch (PDOException $e) { 
    die('Could not connect to database.'); 
} 

$dbh->beginTransaction(); 

try { 
    $stm = $dbh->prepare("SELECT field FROM table WHERE ID = ? FOR UPDATE"); 
    $stm->execute(array($value)); 
    $dbh->commit(); 
} catch (PDOException $e) { 
    $dbh->rollBack(); 
} 

如果必須使用陳舊mysql_ *功能,您可以像:

mysql_query('SET AUTOCOMMIT=0'); 
mysql_query('START TRANSACTION'); 
mysql_query($sql); 
mysql_query('SET AUTOCOMMIT=1'); 
+2

不要在沉默中冷靜下來。留下評論以幫助更好的答案。 – webbiedave 2012-03-22 16:07:57

+2

爲了記錄我看到這個建議沒有問題,它是前瞻性的! – Paul 2013-01-26 13:24:24

0

,則不應使用MySQL的API,因爲它很容易犯錯誤,使SQL的注射和等,以及它缺少一些功能。我懷疑事務是其中之一,因爲如果我沒有錯,每個查詢都是「自己」發送的,而不是在更大的上下文中發送的。

然而,解決方案是使用一些其他的API,我更喜歡mysqli,因爲它如此類似於mysql並得到廣泛支持。您也可以輕鬆地重寫代碼以使用mysqli。

對於事務功能,將自動提交設置爲false,並在您需要時自行提交。這與啓動和停止事務相同。

對於參考一下:

http://www.php.net/manual/en/mysqli.autocommit.php

http://www.php.net/manual/en/mysqli.commit.php

9

的問題是不是你的代碼的語法,但這樣你要使用它。

的記錄顯示爲編輯我鎖定用下面的代碼

從這我假設你選擇和記錄之前「鎖定」的行,然後顯示編輯頁面您的用戶,然後當他們提交它保存的更改並「解鎖」表格。這是根本問題。當你的頁面加載完成後,PHP退出並關閉MySQL連接。發生這種情況時,所有的鎖都會立即釋放。這就是爲什麼控制檯似乎表現得與你的PHP不同。控制檯中的等價物就是你退出程序。

您無法鎖定表格行以進行長時間的編輯。這不是他們的設計。如果您想鎖定一條記錄進行編輯,則需要在另一個表中追蹤這些鎖。創建一個名爲「edit_locks」的新表,並存儲被鎖定的記錄ID,用戶ID編輯以及鎖定的時間。當您想要打開一條記錄進行編輯時,請鎖定整個edit_locks表,然後查詢該記錄是否被其他人鎖定。如果不是,請插入您的鎖定記錄,如果是,則顯示鎖定的錯誤。當用戶保存或取消時,從edit_locks中刪除鎖定記錄。如果你想讓事情變得簡單,只要你的程序想要使用它就鎖定這張表。這將幫助您避免競爭狀況。

還有一種情況會導致問題。如果用戶打開一條記錄進行編輯,然後關閉瀏覽器而不保存或取消,編輯鎖將永遠停留在那裏。這就是爲什麼我說商店被鎖定的時間。編輯本身應該每2分鐘發一個AJAX調用來說「我仍然需要鎖!」。當PHP程序收到這個「重新鎖定」請求時,它應該搜索該鎖,然後將時間戳更新爲當前時間戳。這樣,鎖上的時間戳總是在2分鐘內保持最新。您還需要創建另一個程序來刪除陳舊的舊鎖。這應該每幾分鐘運行一次cron作業。它應該搜索任何超過5分鐘左右時間戳的鎖,然後刪除。如果時間戳比這個更早,那麼編輯器顯然會在2分鐘內關閉一些如何或時間戳是最新的。

像其他人提到的一樣,你應該嘗試使用mysqli。它代表「MySQL改進」並代替舊界面。

+0

這樣做有幾個優點,但也有一些缺點。您需要時常清理鎖定/解鎖表格。這是由崩潰或意想不到的破壞引起的。我個人不會使用它。 – Andreas 2012-03-21 23:48:28

+0

好的JMack,你現在已經擴展了你的答案,並解釋了你的第二部分的缺點。堅實的答案+1 – Andreas 2012-03-21 23:50:44

+0

@Andreas我的描述中包含了清理鎖定表的方法,以便任何瀏覽器崩潰都會導致不超過幾分鐘的記錄鎖定。 – 2012-03-21 23:51:34

0

這是一個老的討論,但也許人們仍在關注它。我使用類似於JMack的方法,但在我想要鎖定的表中包含鎖定信息。我的新列是LockTime和LockedBy。要嘗試一把鎖,我做的:

UPDATE table 
SET LockTime='$now',LockedBy='$Userid' 
WHERE Key='$value' AND (LockTime IS NULL OR LockTime<'$past' OR LockedBy='$Userid') 

($過去的4分鐘前)

如果失敗了,別人有鎖。我可以明確地解鎖,或者讓我的鎖過期:

UPDATE table 
SET LockTime=NULL,LockedBy='' 
WHERE Key='$value' AND LockedBy='$Userid' 

cron作業可以刪除舊的鎖,但它並不是真的有必要。