Хронические устаревшие результаты с использованием MySQLdb в Python - PullRequest
21 голосов
/ 10 мая 2011

Моя программа на Python запрашивает набор таблиц в БД MySQL, спит 30 секунд, затем запрашивает их снова и т. Д. Соответствующие таблицы постоянно обновляются сторонней организацией, и (очевидно) я хотел бы видеть новые результаты каждые 30 секунд.

Допустим, мой запрос выглядит так:

"select * from A where A.key > %d" % maxValueOfKeyFromLastQuery

Регулярно я вижу, что моя программа перестает находить новые результаты после одной или двух итераций, хотя новые строки присутствуют в таблицах . Я знаю, что в таблицах присутствуют новые строки, потому что я вижу их, когда выдаю идентичный запрос из интерактивного mysql (т.е. не из Python).

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

Я подумал, что это может быть проблема кэширования на стороне сервера, как обсуждалось здесь: Явное отключение кэша запросов MySQL в некоторых частях программы

Тем не менее:

  1. Когда я проверяю интерактивную оболочку mysql, она говорит, что кэширование включено. (Так что, если это проблема с кэшированием, почему интерактивная оболочка не страдает от этого?)

  2. Если я явно выполняю SET SESSION query_cache_type = OFF из своей программы на Python, проблема все равно возникает.

Создание нового соединения с БД для каждого запроса - единственный способ устранить проблему.

Как я могу получить свои запросы от Python, чтобы увидеть новые результаты, которые, я знаю, есть?

Ответы [ 3 ]

23 голосов
/ 10 мая 2011

Этот веб-сайт и Этот веб-сайт содержат информацию по той же проблеме. Чтобы поддерживать ваши таблицы в актуальном состоянии, вы должны фиксировать свои транзакции. Используйте db.commit(), чтобы сделать это.

Как уже упоминалось в сообщении ниже, вы можете убрать эту необходимость, включив авто-фиксацию. это можно сделать, запустив db.autocommit(True)

Кроме того, автоматическая фиксация включена в интерактивной оболочке, поэтому это объясняет, почему у вас не возникла проблема.

13 голосов
/ 15 апреля 2013

Возможно, вы захотите проверить уровень изоляции транзакций в вашей базе данных. Поведение, которое вы описываете, - это то, что вы можете ожидать, если для него установлено значение REPEATABLE-READ. Вы можете изменить его на READ-COMMITTED.

Поскольку в первоначальном постере проблемы упоминается, что он просто запрашивает базу данных, это не может быть забытый коммит. Вставка коммита кажется обходным решением, поскольку он вызывает начало новой транзакции; и новый снимок может потребоваться установить. Тем не менее, необходимость вставлять коммит перед каждым выбором не кажется мне хорошей практикой программирования.

Нет кода Python для отображения, так как решение заключается в правильной настройке базы данных.

DO проверьте документацию MySQL по адресу http://dev.mysql.com/doc/refman/5.5/en/set-transaction.html.

ПОВТОРЯЮЩАЯ ЧТЕНИЕ
Это уровень изоляции по умолчанию для InnoDB. Для согласованных чтений существует важное отличие от уровня изоляции READ COMMITTED: все согласованные чтения в одной транзакции считывают моментальный снимок, созданный при первом чтении. Это соглашение означает, что если вы выполняете несколько простых (неблокирующих) операторов SELECT в одной транзакции, эти операторы SELECT также согласуются друг с другом. См. Раздел 14.3.9.2, «Согласованные считывания без блокировки».

ПРОЧИТАЙТЕ ОБЯЗАТЕЛЬНО
Отчасти Oracle-подобный уровень изоляции в отношении согласованных (неблокирующих) чтений: каждое согласованное чтение, даже в рамках одной и той же транзакции, устанавливает и считывает свой собственный свежий снимок. См. Раздел 14.3.9.2, «Согласованные считывания без блокировки».

Проверка настроенного уровня изоляции:

>mysql > SELECT @@GLOBAL.tx_isolation, @@tx_isolation;
+-----------------------+-----------------+
| @@GLOBAL.tx_isolation | @@tx_isolation  |
+-----------------------+-----------------+
| REPEATABLE-READ       | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set (0.01 sec)

Установка уровня изоляции транзакции READ-COMMITTED

mysql> SET GLOBAL tx_isolation='READ-COMMITTED';
Query OK, 0 rows affected (0.00 sec)

mysql> SET SESSION tx_isolation='READ-COMMITTED';
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @@GLOBAL.tx_isolation, @@tx_isolation;
+-----------------------+----------------+
| @@GLOBAL.tx_isolation | @@tx_isolation |
+-----------------------+----------------+
| READ-COMMITTED        | READ-COMMITTED |
+-----------------------+----------------+
1 row in set (0.01 sec)

mysql>

И снова запустить приложение ...

9 голосов
/ 10 мая 2011

Вы можете включить автоматическую фиксацию автоматически в MySQLdb!Попробуйте следующее:

conn = MySQLdb.Connect("host", "user", "password")
conn.autocommit(True)

Это дает вам то же поведение, к которому вы привыкли в интерактивной оболочке.

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