2011-03-04 148 views
1

你好,與學說ORM遞歸 - 邏輯錯誤

我有種每日隨機圖像系統建立與Codeigniter和Doctrine。

有一個關鍵功能,它返回每日圖像或設置一個新的。我正在使用遞歸調用,但有時是兩個圖像選擇一天

class Daily extends Controller { 

    function find_daily(){ 
     $connection = Doctrine_Manager::connection(); 
     $connection->setCharset('utf8'); 

     $q = Doctrine_Query::create() 
      ->select('COUNT(id) as dailycount') 
      ->from('Image') 
      ->where('daily_date = ?',date("Y-m-d")); 



     $set = $q->execute(); 

     if($set[0]->dailycount != 0){ //theres one or more for today 



      $q = Doctrine_Query::create() 
      ->select('id') 
      ->from('Image') 
      ->where('daily_date = ?',date("Y-m-d")) 
      ->limit(1); 


      $set = $q->execute(); 
      $i = Doctrine::getTable('Image')->findOneById($set[0]["id"]); 

      return $i; 

      }else { // none image selected with today date 


       $q = Doctrine_Query::create() 
       ->select('id') 
       ->from('Image') 
       ->where('daily_date = ?', "0000-00-00") 
       ->andWhere("dir =?","queue") 
       ->orderBy("rand()") 
       ->limit(1); 


       $set = $q->execute(); 


       $i = Doctrine::getTable('Image')->findOneById($set[0]["id"]); 

       $i->daily_date = date("Y-m-d"); 
       $i->dir = "archive"; 
       $i->save(); 

       $this -> find_daily(); 
       }; 

     } 

... 

我覺得那裏有一些愚蠢的錯誤..也許叫什麼「主義:: doAllAndClear」 $this -> find_daily();之前或我忘了什麼東西......

還是最好不要使用遞歸調用?

謝謝。

+0

忍受我,因爲我可能只是被你的代碼弄糊塗了,但你爲什麼要遞歸?爲什麼不說,只是'返回$我;'而不是再次調用'$ this-> find_daily()'?另外,如果你遞歸,那麼無論你打電話給你什麼都不會收到回報價值,是嗎?因爲你沒有返回遞歸調用的結果。我們可能需要查看函數的其餘部分來確定發生了什麼。 – 2011-03-04 12:01:18

+0

另外,這段代碼如何被啓動?有兩個用戶同時運行這個機會嗎? – 2011-03-04 12:01:57

+0

@matt你是對的我可以做到這一點沒有遞歸...我可以這樣做,但我會很高興找到我做錯了什麼。當某些用戶查看日常圖像時使用此代碼。我有約10名用戶(項目不公開)。我的表是時間戳 - 並且同時選擇兩個圖像(db行更新)。我認爲,現在同一時間(午夜)有兩名用戶並不是可能的(此問題反覆出現)。 – 2011-03-04 12:28:18

回答

0

嗯,我還沒有測試過這個,但我可能更有可能像這樣寫你的代碼;希望這會給你一些想法:

function find_daily() { 
    $connection = Doctrine_Manager::connection(); 
    $connection->setCharset('utf8'); 

    // Make sure "today" doesn't change while the script runs 
    $today = date("Y-m-d"); 

    // Find an image with today's date. 
    $q = Doctrine_Query::create() 
     ->from('Image') 
     ->where('daily_date = ?', $today) 
     ->limit(1); 

    $image = $q->fetchOne(); 

    if (!$image) { 
     // There was no image with today's date, so pick one from the queue at random instead. 
     $q = Doctrine_Query::create() 
     ->from('Image') 
     ->where('daily_date = ?', "0000-00-00") 
     ->andWhere("dir =?","queue") 
     ->orderBy("rand()") 
     ->limit(1); 

     $image = $q->fetchOne(); 
     // ToDo: Cope with there being no image in the queue 

     $image->setDailyDate($today); 
     $image->setDir("archive"); 
     $image->save(); 
    } 
    return $image; 
    } 

但是,你需要考慮一下會發生什麼,如果兩個人打你的腳本在同一時間。在這種情況下,他們可能會取一個新的形象的一天(因爲他們可以各自在同一時間運行第一SELECT,都得到一個結果,說有沒有日常照片呢。)

爲了避免我猜你會想把它包裝在一個事務中,並設置一個事務隔離級別,以使該函數的第一個調用者「贏得」競爭條件,並且隨後的調用者阻塞,直到更新安全地保存。不完全確定你會如何做到這一點,但它不應該很難。

檢查手冊中,beginTransaction()在開始時,commit()末,一切之前,設置其他涉及$tx = $conn->transaction; $tx->setIsolation('SERIALIZABLE');(另有兩個用戶很可能仍運行一次選擇),很可能是你所需要的,但你可能要等待真正知道學說的人對此發表評論...

我還在腳本的開頭保存了「今天」的日期,否則在SELECT和期間會有不同的危險稍後更新,如果腳本跨午夜運行。

+0

謝謝,交易對我來說是全新的。我改變我的代碼,以避免這種愚蠢的遞歸。 – 2011-03-04 14:48:55

+0

@Jan想一想,我並不完全相信交易會在這裏完成這項工作;您正在查看整個表的前一個結果(查找是否存在具有今天日期的任何行)的更新。在此函數運行時鎖定表會執行該任務,但您可能需要等待並查看是否在接受答案之前,任何人都有更好的想法。 – 2011-03-04 15:19:57

+0

等待那正是我現在正在做的:)它的小項目 - 所以我可以負擔得起。謝謝。 – 2011-03-04 15:22:40