Поэтому я использую psycopg2, у меня есть простая таблица:psycopg2 иногда возвращает нуль
CREATE TABLE IF NOT EXISTS feed_cache (
feed_id int REFERENCES feeds(id) UNIQUE,
feed_cache text NOT NULL,
expire_date timestamp --without time zone
);
Я звоню следующий метод и запрос:
@staticmethod
def get_feed_cache(conn, feed_id):
c = conn.cursor()
try:
sql = 'SELECT feed_cache FROM feed_cache WHERE feed_id=%s AND localtimestamp <= expire_date;'
c.execute(sql, (feed_id,))
result = c.fetchone()
if result:
conn.commit()
return result[0]
else:
print 'DBSELECT.get_feed_cache: %s' % result
print 'sql: %s' % (c.mogrify(sql, (feed_id,)))
except:
conn.rollback()
raise
finally:
c.close()
return None
Я добавил else, чтобы вывести точный sql и результат, который выполняется и возвращается.
Метод get_feed_cache() вызывается из пула потоков подключения к базе данных. Когда метод get_feed_cache() называется «медленным» (~ 1/sec или меньше), результат возвращается как ожидалось, однако при вызове одновременно он будет иногда return None. Я пробовал несколько способов написания этого запроса &.
Некоторые наблюдения:
- Если удалить 'И localtimestamp < = expire_date' из запроса, запрос всегда возвращает результат.
- Выполнение запроса быстро в последовательном порядке в psql всегда возвращает результат.
- После прочтения методов fetch *() класса курсора psycopg они отмечают, что результаты кэшируются для курсора, я предполагаю, что кеш не используется между разными курсорами. http://initd.org/psycopg/docs/faq.html#best-practices
- Я попытался использовать функции postgresql now() и current_timestamp с теми же результатами. (Теперь я сознаю часовой пояс аспекта() & current_timestamp)
Условия отметить:
- Там никогда не будет случаем, когда не существует значение feed_cache для предоставленного FEED_ID.
- Там никогда не будет случай, когда какое-либо значение в таблице feed_cache является NULL
- время тестирования я полностью отключить любые & все записи в этой таблице
- Я поставил expire_date быть достаточно далеко в будущем все значения такие, что выражение 'AND localtimestamp < = expire_date' всегда будет истинным.
Вот копия & вставили выход из него не возвращаются None:
DBSELECT.get_feed_cache: None
sql: SELECT feed_cache FROM feed_cache WHERE feed_id=5 AND localtimestamp < expire_date;
Ну, что в значительной степени это, я не знаю, что происходит. Возможно, я делаю какую-то туманную ошибку, и я просто этого не замечаю! Моя нынешняя гипотеза заключается в том, что она имеет какое-то отношение к psycopg2 и, возможно, к тому, как она кэширует результаты между курсорами. Если курсоры DO разделяют кеш и запросы происходят одновременно, то возможно, что первый курсор извлекает результат, второй курсор видит, что есть кеш одного и того же запроса, поэтому он не выполняется, затем первый курсор закрывает и удаляет кеш, а второй курсор пытается получить кеш теперь null/None. *
При этом psycopg2 заявляет, что он является потокобезопасным для запросов только для чтения, поэтому, если я не интерпретирую их выполнение поточно-безопасных, это не должно быть так.
Благодарим вас за внимание!
* После добавления блокировки потоков для get_feed_cache, приобретая перед созданием курсора и отпуская, прежде чем вернуться, я до сих пор иногда получаю Отсутствует результат
Вы абсолютно уверены, что в таблице нет значений NULL? Что говорит 'SELECT * FROM feed_cache WHERE feed_cache IS NULL'? Я спрашиваю об этом, потому что ваш код кажется прекрасным, и я чувствую, что в ваших данных что-то не так. – fog
SELECT * FROM feed_cache WHERE feed_cache IS NULL; feed_id | feed_cache | expire_date --------- + ------------ + ------------- (0 строк) – lanthica
Извините за форматирование, 0 строк были возвращены. – lanthica