所以我使用的psycopg2,我有一個簡單的表:psycopg2偶爾返回null
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()方法被稱爲「slowishly」(〜1/sec或更少)時,結果會按預期返回,但當同時調用時,它將會偶爾返回無。我已經嘗試了多種方法來編寫這個查詢&方法。
一些觀察:
- 如果我刪除 '和LOCALTIMESTAMP < = EXPIRE_DATE' 從查詢,查詢總是返回的結果。
- 在psql中以串行方式快速執行查詢總是返回一個結果。
- 閱讀了psycopg的遊標類的fetch *()方法後,他們注意到遊標的緩存結果,我假設緩存不是在不同的遊標之間共享的。 http://initd.org/psycopg/docs/faq.html#best-practices
- 我已經嘗試使用postgresql的now()和current_timestamp函數獲得相同的結果。 (我知道的時區方面的NOW()& CURRENT_TIMESTAMP)
條件需要注意:
- 永遠不會有這樣的情況:沒有一個提供FEED_ID一個feed_cache值。
- 永遠不會有這樣的情況:在feed_cache表中的任何值爲NULL
- 測試時我已經完全禁止任何&所有寫入該表
- 我在將來足夠遠的設置EXPIRE_DATE成爲所有表達式'AND localtimestamp < = expire_date'將始終爲真。
這裏是它返回無副本&粘貼輸出:
DBSELECT.get_feed_cache: None
sql: SELECT feed_cache FROM feed_cache WHERE feed_id=5 AND localtimestamp < expire_date;
嗯,這是相當多了,我不知道發生了什麼事。也許我正在犯一些非常愚蠢的錯誤,我只是沒有注意到它! 我目前的猜測是它與psycopg2有關,也許它是在遊標之間緩存結果的方式。如果遊標DO共享緩存並且查詢幾乎同時發生,那麼第一個遊標可能會提取結果,第二個遊標可能會看到相同查詢的緩存,因此它不會執行,那麼第一個遊標關閉並刪除緩存,第二個遊標嘗試獲取現在爲空/無緩存。 *
也就是說,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 rows) – lanthica
對不起格式化,0行被退回。 – lanthica