Почему две параллельные транзакции не блокируют друг друга?

Темы, не касающиеся фреймворка, но относящиеся к программированию в целом.
Ответить
websiller
Сообщения: 29
Зарегистрирован: 2014.04.15, 17:30

Почему две параллельные транзакции не блокируют друг друга?

Сообщение websiller »

Есть простой контроллер:

Код: Выделить всё

public function actionIndex()
    {
  $model = Counter::model();
  $transaction = $model->dbConnection->beginTransaction();
  $Counter = $model->findByPk(1);

  $Counter->value++;
  sleep(10);
  $Counter->save();
  $transaction->commit();

  $this->render('index');
    }

Изначально поле "value" в таблице Counter равно 0. Так вот если запустить такой контроллер два раза и одновременно, то по завершению выполнения обоих контроллеров в поле "value" будет стоять значение 1. Получается, транзакции при одновременном выполнении двух контроллеров не блокируют друг друга, а выполняются параллельно. В итоге они обе получают ноль, ждут 10 секунд, а потом записывают обновленное значение, то есть 1. Но мне нужно, чтобы в результате получалась двойка.То есть, чтобы когда начиналась первая транзакция, то вторая блокировалась бы и уже после завершения первой, запускалась вторая, получая обновленное значение (1), увеличивала бы его еще на 1 и уже записывала в поле значение "2".
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Почему две параллельные транзакции не блокируют друг друга?

Сообщение zelenin »

транзакции здесь не причем и решают другие проблемы. Это race condition. Два запроса одновременно получают одинаковое значение счетчика и инкрементят его через 10 секунд. Для корректной работы они должны отработать последовательно.
websiller
Сообщения: 29
Зарегистрирован: 2014.04.15, 17:30

Re: Почему две параллельные транзакции не блокируют друг друга?

Сообщение websiller »

А как возможно реализовать эту последовательность? Каким инструментом?
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Почему две параллельные транзакции не блокируют друг друга?

Сообщение zelenin »

websiller писал(а):А как возможно реализовать эту последовательность? Каким инструментом?
optimistic/pessimistic lock
yan
Сообщения: 942
Зарегистрирован: 2011.03.23, 09:28
Откуда: Уфа

Re: Почему две параллельные транзакции не блокируют друг друга?

Сообщение yan »

насчет активрекорда не в курсе, а как поможет здесь например http://www.mysql.ru/docs/man/InnoDB_locking_reads.html
Для этого случая возможны два способа произвести чтение и увеличить значение счетчика: (1) сначала обновить значение счетчика, увеличив его на 1, и только после этого прочитать его или (2) сначала прочитать счетчик в режиме блокировки FOR UPDATE, а после этого увеличить его значение:

SELECT COUNTER_FIELD FROM CHILD_CODES FOR UPDATE;
UPDATE CHILD_CODES SET COUNTER_FIELD = COUNTER_FIELD + 1;

Оператор SELECT ... FOR UPDATE прочитает последние доступные данные с установкой отдельной блокировки на каждую считываемую строку.
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Почему две параллельные транзакции не блокируют друг друга?

Сообщение zelenin »

yan писал(а):насчет активрекорда не в курсе
тогда ответьте на вопрос темы
yan писал(а):а как поможет здесь например http://www.mysql.ru/docs/man/InnoDB_locking_reads.html
Для этого случая возможны два способа произвести чтение и увеличить значение счетчика: (1) сначала обновить значение счетчика, увеличив его на 1, и только после этого прочитать его или (2) сначала прочитать счетчик в режиме блокировки FOR UPDATE, а после этого увеличить его значение:

SELECT COUNTER_FIELD FROM CHILD_CODES FOR UPDATE;
UPDATE CHILD_CODES SET COUNTER_FIELD = COUNTER_FIELD + 1;

Оператор SELECT ... FOR UPDATE прочитает последние доступные данные с установкой отдельной блокировки на каждую считываемую строку. Таким образом, блокировка на строки устанавливается точно так же, как и в случае поиска по UPDATE.
в постгресе нет такого метода.
yan
Сообщения: 942
Зарегистрирован: 2011.03.23, 09:28
Откуда: Уфа

Re: Почему две параллельные транзакции не блокируют друг друга?

Сообщение yan »

zelenin писал(а): тогда ответьте на вопрос темы
это тоже тогда не ответ
optimistic/pessimistic lock
именно в активрекорде такого инструмента нет насколько знаю
в постгресе нет такого метода
не вижу чтобы упоминался постгрес в вопросе, пусть уж автор темы решит подходит ему это решение или нет
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Почему две параллельные транзакции не блокируют друг друга?

Сообщение zelenin »

yan писал(а):
optimistic/pessimistic lock
именно в активрекорде такого инструмента нет насколько знаю
а) opt. lock реализовывается на любом db-слое без проблем, т.к. подразумевает под собой введение доп. колонки
б) ну и он реализован
yan писал(а):не вижу чтобы упоминался постгрес в вопросе, пусть уж автор темы решит подходит ему это решение или нет
потому что упоминался AR, являющийся абстракцией над БД. Если речь об абстракции, то vendor-specific решения попахивают. Ну и о mysql речи тоже не шло.
Ответить