Intereting Posts

SELECT и заблокируйте строку, а затем UPDATE

У меня есть сценарий, который выбирает строку из базы данных MySQL. Затем обновляет эту строку. Как это:

$statement = $db->prepare("SELECT id, link from persons WHERE processing = 0"); $statement->execute(); $row = $statement->fetch(); $statement = $db->prepare("UPDATE persons SET processing = 1 WHERE id = :id"); $success = $statement->execute(array(':id' => $row['id'])); 

Сценарий вызывает этот PHP-код несколько раз одновременно. И иногда он выбирает строку, хотя она должна быть «processing = 1», потому что другой скрипт вызывает ее в точное время.

Как я могу избежать этого?

Что вам нужно сделать, так это добавить какой-то замок, чтобы предотвратить условия гонки, подобные тем, которые вы создали:

 UPDATE persons SET processing=1 WHERE id=:id AND processing=0 

Это позволит избежать двойной блокировки.

Чтобы это еще больше улучшить, создайте столбец блокировки, который вы можете использовать для утверждения:

 UPDATE persons SET processing=:processing_uuid WHERE processing IS NULL LIMIT 1 

Для этого требуется VARCHAR , индексированный столбец processing используемый для утверждения, который имеет значение по умолчанию NULL . Если вы получите строку, измененную в результатах, вы заявили запись и можете пойти и работать с ней, используя:

 SELECT * FROM persons WHERE processing=:processing_uuid 

Каждый раз, когда вы пытаетесь потребовать, создайте новый ключ UUID претензии.

Попробуйте использовать транзакции для своих запросов. Читайте о них на сайте mysql dev

Вы можете обернуть свой код:

 $dbh->beginTransaction(); // ... your transactions here $dbh->commit(); 

Здесь вы найдете документацию.

Использовать SELECT FOR UPDATE

http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html

например

SELECT counter_field FROM child_codes FOR UPDATE; UPDATE child_codes SET counter_field = counter_field + 1;

Оберните это в транзакцию, и блокировки будут освобождены при завершении транзакции.