Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
Несколько запросов параллельно могу сравнить и получить разрешение на закачку.
Вытекающие будут из serializable.
А на счет read committed + select with shared lock, это уже несколько другая плоскость. Тут требуются явные дополнительные действия
Ну и требуется отлавливать падения на дедлоках (именно так оно выглядит в случае MySQL) и запускать транзакцию снова и снова, пока она таки не пройдет успешно.
А когда мы выходим за пределы БД, использование транзакций для синхронизации может стать проблемой.
Транзакция внутри себя использует блокировки
Кстати, в задаче со счетчиком достаточно уровня изоляции repeatable read.
Вообще, исходная задача транзакции несколько иная — обеспечить возможность отката пачки изменений. А не синхронизация.
Не достаточно. Очень легко запустить приведенный по ссылкам выше код на любой машине, где есть PHP и MySQL. А после просто удалить файл и выполнить блок очистки, чтобы мусора не осталось. Попробуйте запустить его с уровнем REPEATABLE READ.
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT `limit`, fact FROM users WHERE id = 1;
+-------+------+
| limit | fact |
+-------+------+
| 2 | 1 |
+-------+------+
1 row in set (0.00 sec)
mysql> UPDATE users SET fact = fact + 1 WHERE id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> COMMIT;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT `limit`, fact FROM users WHERE id = 1;
+-------+------+
| limit | fact |
+-------+------+
| 2 | 3 |
+-------+------+
1 row in set (0.00 sec)
REPEATABLE READ ничего не блокирует.
REPEATABLE READ
Specifies that statements cannot read data that has been modified but not yet committed by other transactions and that no other transactions can modify data that has been read by the current transaction until the current transaction completes.
они не работают по умолчанию, т.е. нужно менять уровень изоляции;
требуется такой уровень изоляции, который под нагрузкой все уложит и преведет к дедлокам на дедлоке в случае MySQL.
Так что не делая здесь хоть какую-то явную блокировку, получаем дырку.
у задачи со счетчиком есть конкретное решение, которое будет прекрасно работать и под нагрузкой
Так вот достаточно добавить ограничение на количество открытых динамических запросов с одного IP и/или от одного пользователя.
И транзакции тут тем более не подойдут.
Так вот достаточно добавить ограничение на количество открытых динамических запросов с одного IP и/или от одного пользователя.… и как вы его сделаете без транзакции?
Т.к. здесь допустима погрешность
Но вообще, если уже придираться, то можно использовать атомарный инкремент в Memcache или Redis.
Ну а можно и просто писать в общую память и использовать примитив синхронизации, если сервер один.
Если погрешность допустима, то можно просто использовать неблокирующее решение, в чем проблема-то?
Погрешность допустима при подсчете количества запросов, которые могут работать одновременно для пользователя и/или IP. Будет их 10 или 12, разницы никакой (ну ~100 Кб памяти разница на время таймаута блокировки).
#1213 - Deadlock found when trying to get lock; try restarting transaction
mysql> SET SESSION tx_isolation='SERIALIZABLE';
Query OK, 0 rows affected (0.00 sec)
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT `limit`, fact FROM users WHERE id = 1;
+-------+------+
| limit | fact |
+-------+------+
| 2 | 3 |
+-------+------+
1 row in set (0.01 sec)
mysql> UPDATE users SET fact = fact + 1 WHERE id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> COMMIT;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT `limit`, fact FROM users WHERE id = 1;
+-------+------+
| limit | fact |
+-------+------+
| 2 | 4 |
+-------+------+
1 row in set (0.00 sec)
mysql>
А блокировки можно делать штатными средствами MySQL, без flock и т.д.
Через несколько лет возможно появится в проектах.
Вот какие реальные юзкейсы, где многопоточность выиграет у многозадачности (=многопроцессности)?
Если это веб-интерфейс, то скорее всего лучше будут асинхронные запросы на проверку каждого агента отдельно. Тогда если один или несколько агентов будут долго отвечать, это будет видно интерактивно.
Тут момент такой, что ждать ответа по сети можно и асинхронно.

Опрос: как у вас решается проблема синхронизации параллельных запросов на PHP?