2011-10-16 28 views
1

我有一張存儲需要處理的數據的表。我在表中有ID,狀態,數據。我目前正在瀏覽並選擇ID,數據where status =#。然後,我在選擇後立即進行更新,更改狀態#以便它不會再次被選中。使用perl處理數據 - 使用mysql選擇更新使用情況

我的程序是多線程的,有時我得到的線程獲取相同的ID,因爲它們都是在相對接近的時間查詢表,導致抓取相同的ID。我看着選擇更新,但是,我做了查詢錯誤,或者我不明白它用於什麼。

我的目標是找到一種方法來抓取id,我需要的數據和設置狀態,以便其他線程不會嘗試抓取和處理相同的數據。這是我試過的代碼。 (我寫它一起爲展示目的在這裏。我有我的準備設置在節目的開始,因爲不這樣做會在每次運行時間進行準備,以防萬一有人擔心那裏)

my $select = $db->prepare("SELECT id, data FROM `TestTable` WHERE _status=4 LIMIT ? FOR UPDATE") or die $DBI::errstr; 
if ($select->execute($limit)) 
    { 
     while ($data = $select->fetchrow_hashref()) 
      { 

       my $update_status = $db->prepare("UPDATE `TestTable` SET _status = ?, data = ? WHERE _id=?"); 
        $update_status->execute(10, "", $data->{_id}); 
     push(@array_hash, $data); 

      } 
    } 

時我運行這個,如果做多線程,我會得到許多重複的插入,當我嘗試做一個插入後,我處理我的交易數據。

我對mysql和我所做的研究並不熟悉,我還沒有找到任何真正解決這個問題的方法。

謝謝

+0

此外,在這樣做的情況下,我可以處理更新或從表中刪除。 – user985590

回答

0

它看起來像你只是依靠數據庫鎖定機制。我用Google搜索perl dbi locking,發現this

$dbh->do("LOCK TABLES foo WRITE, bar READ"); 
$sth->prepare("SELECT x,y,z FROM bar"); 
$sth2->prepare("INSERT INTO foo SET a = ?"); 
while (@ary = $sth->fetchrow_array()) { 
    $sth2->$execute($ary[0]); 
    } 
$sth2->finish(); 
$sth->finish(); 
$dbh->do("UNLOCK TABLES"); 

不是真的說GIYF因爲我也是新手相當,在MySQL和DBI,但也許你可以找到其他的答案的方式。

另一種選擇可能如下,只有在控制訪問數據的所有代碼時纔有效。您可以在表格中創建lock列。當你的代碼訪問表是(僞):

if row.lock != 1 
    row.lock = 1 
    read row 
    update row 
    row.lock = 0 
    next 
else 
    sleep 1 
    redo 

雖然再次,這個相信在訪問此數據的所有用戶/腳本將同意遵守這一政策。如果你不能確保那麼這是行不通的。

無論如何,這就是關於這個話題的所有知識。祝你好運!

+0

我不知道如果鎖定表是最好的選擇。然後它會減慢使用同一個表的其他代碼集。我更需要鎖定一個特定的行。 – user985590

+0

@ user985590,更新了,它不是一個很好的答案,但也許在沒有更好的東西的情況下... –

1

作爲一個健全的檢查,你使用InnoDB嗎?除了使用全表鎖定來僞造MyISAM外,MyISAM沒有事務支持。

我沒有看到您開始交易的位置。默認情況下,MySQL的autocommit選項處於打開狀態,因此,除非您關閉autocommit,否則啓動事務並稍後提交將是必需的。

+0

我使用的是mysql和autocommit。我不明白你的意思是說「我沒有看到你開始交易的地方」你能澄清一下嗎? – user985590

+0

完成後,您需要調用'START TRANSACTION'然後執行'COMMIT'。 –

+0

另外,你說你正在穿線這件事。 「SELECT ... FOR UPDATE」和「UPDATE」查詢是否發生在同一個線程中,每個線程都有自己的連接? –