SQLAlchemy не возвращает выбранные данные - PullRequest
1 голос
/ 30 ноября 2009

Я использую SQLAlchemy в качестве ORM в приложении, которое я создавал в течение некоторого времени.

Пока что реализовать и использовать ORM было довольно безболезненно, однако для недавней функции, над которой я работаю, требуется реализация в стиле постоянных и распределенных очередей (list & worker), которую я встроил в MySQL и Python. .

Все это работало довольно хорошо, пока я не протестировал его в масштабируемой среде. Я использовал блокировку на уровне строк InnoDB, чтобы гарантировать, что каждая строка читается только один раз, в то время как строка заблокирована, я обновляю значение 'in_use', чтобы убедиться, что другие не хватают запись.

Поскольку MySQL не предлагает метод "NOWAIT", как Postgre или Oracle, я столкнулся с проблемами блокировки, когда рабочие потоки зависают и ждут, когда заблокированная строка станет доступной.

В попытке преодолеть это ограничение я попытался объединить всю необходимую обработку в одном операторе и запустить его с помощью метода execute() ORM, хотя SQLAlchemy отказывается возвращать результат запроса.

Вот пример.

Мой оператор SQL:

SELECT id INTO @update_id FROM myTable WHERE in_use=0 ORDER BY id LIMIT 1 FOR UPDATE;
UPDATE myTable SET in_use=1 WHERE id=@update_id;
SELECT * FROM myTable WHERE id=@update_id;

И я запускаю этот код в консоли:

engine = create_engine('mysql://<user details>@<server details>/myDatabase', pool_recycle=90, echo=True)
result = engine.execute(sqlStatement)
result.fetchall()

Только чтобы получить этот результат

[]

Я уверен, что оператор выполняется, поскольку я вижу, как обновление вступает в силу в базе данных, и если я выполняю его через терминал mysql или другие инструменты, я получаю измененную строку, возвращаемую. Кажется, это просто SQLAlchemy, который не хочет подтверждать возвращенную строку.

Есть ли что-то конкретное, что нужно сделать, чтобы ORM принял ответ?

Приветствия

1 Ответ

3 голосов
/ 30 ноября 2009

Вы выполнили 3 запроса, и MySQLdb создает набор результатов для каждого. Вы должны получить первый результат, затем вызвать cursor.nextset(), получить второй и так далее.

Это отвечает на ваш вопрос, но не будет полезным для вас, потому что не решит проблему блокировки. Сначала вы должны понять, как работает FOR UPDATE: он блокирует возвращенные строки до конца транзакции. Чтобы избежать длительного ожидания блокировки, вы должны сделать его как можно короче: SELECT ... FOR UPDATE, UPDATE SET in_use=1 ..., COMMIT. На самом деле вам не нужно помещать их в один оператор SQL, 3 execute() вызовы тоже будут в порядке. Но вам придется выполнить коммит перед долгим вычислением, иначе блокировка будет удерживаться слишком долго, и обновление in_use (автономная блокировка) не имеет смысла. И конечно, вы можете сделать то же самое, используя ORM.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...