Проблема параллелизма - PullRequest
       10

Проблема параллелизма

3 голосов
/ 01 июня 2009

У меня возникли проблемы с параллелизмом при использовании MySQL и PHP + Propel 1.3. Ниже приведен небольшой пример метода «save» объекта Propel.

public function save(PropelPDO $con = null) {
    $con = Propel::getConnection();
    try {
        $con->beginTransaction();
        sleep(3); // ignore this, used for testing only
        parent::save($con);
        $foo = $this->getFoo(); // Propel object, triggers a SELECT

        // stuff is happening here...

        $foo->save($con);
        $con->commit();
    } catch (Exception $e) {
        $con->rollBack();
        throw $e;
    }
}

Проблема в объекте $ foo. Допустим, мы получаем два вызова примера метода один за другим в очень короткое время. В некоторых случаях, если вторая транзакция читает $ foo ...

$foo = $this->getFoo();

... до того, как первая транзакция смогла сохранить ее ...

$foo->save($con);

... $ foo, прочитанный во второй транзакции, устареет, и произойдут плохие вещи.

Как заставить блокировать таблицу, в которой хранятся объекты Foo, чтобы последующие транзакции могли читать из нее только после того, как первая закончила свою работу?

РЕДАКТИРОВАТЬ: контекст представляет собой веб-приложение. Короче говоря, в некоторых случаях я хочу, чтобы самый первый запрос выполнял некоторую модификацию данных (что происходит между получением и сохранением $ foo). Все последующие запросы не должны быть в состоянии сделать изменения. Произойдет ли изменение или нет, зависит от извлеченного состояния $ foo (атрибут строки таблицы). Если две транзакции извлекают один и тот же $ foo, модификация будет выполняться дважды, что вызывает проблему.

Ответы [ 2 ]

1 голос
/ 01 июня 2009

когда вы загружаете эту существующую строку в экран / приложение, также загружайте LastChgDate. когда вы сохраняете его, используйте «AND LastChgDate = thevalue ». проверьте количество строк в обновлении, если оно равно нулю, верните сообщение об ошибке «кто-то другой уже сохранил эту запись», откат и другие изменения. С этой логикой вы можете сохранить строку только в том случае, если она была загружена. для новых строк INSERT это необязательно, потому что они новые.

0 голосов
/ 01 июня 2009

В MySQL, я думаю, вы можете использовать SELECT FOR UPDATE для выполнения блокировки.

Другой вариант - использовать вызовы функций MySQL GET_LOCK и RELEASE_LOCK для создания именованных блокировок, которые вы использовали бы для управления доступом к ресурсу.

Есть некоторые недостатки этих подходов. Я сам не очень часто их использовал, и они специфичны для MySQL, но они могли бы работать на вас.

...