2009-07-27 94 views
4

我的Django的網站最近開始從我的緩存代碼拋出錯誤,我想不通爲什麼...Django的cache.set()導致重複鍵錯誤

我打電話:

from django.core.cache import cache 
cache.set('blogentry', some_value) 

而且Django在拋出的錯誤是:

TransactionManagementError: This code isn't under transaction management 

但看PostgreSQL數據庫日誌,似乎從這個錯誤中幹:

STATEMENT: INSERT INTO cache_table (cache_key, value, expires) VALUES (E'blogentry', E'pickled_version_of_some_value', E'2009-07-27 11:10:26') 
ERROR: duplicate key value violates unique constraint "cache_table_pkey" 

對於我的生活,我無法弄清楚爲什麼Django試圖做INSERT而不是UPDATE。有什麼想法嗎?

cursor.execute("SELECT cache_key, expires FROM %s WHERE cache_key = %%s" % self._table, [key]) 
try: 
    result = cursor.fetchone() 
    if result and (mode == 'set' or 
      (mode == 'add' and result[1] < now)): 
     cursor.execute("UPDATE %s SET value = %%s, expires = %%s WHERE cache_key = %%s" % self._table, [encoded, str(exp), key]) 
    else: 
     cursor.execute("INSERT INTO %s (cache_key, value, expires) VALUES (%%s, %%s, %%s)" % self._table, [key, encoded, str(exp)]) 

所以我說,你正在做的INSERT INTO,而不是更新,因爲結果計算爲false:

+0

是不是緩存到數據庫有一種破壞緩存的目的? – thedz 2009-07-27 21:52:07

+4

取決於你正在緩存什麼。 – 2009-07-27 22:14:36

+0

我將它編輯爲「blogentry」,但它實際上緩存了博客邊欄小部件的大量相關數據。 – 2009-07-27 23:54:07

回答

4

這是一場典型的比賽。它會檢查您插入的密鑰是否存在;如果沒有,它會執行插入,但其他人可以在計數和插入之間插入密鑰。事務不會阻止這一點。

該代碼似乎期望這一點,並嘗試處理它,但是當我查看代碼來處理這種情況時,我可以立即看到它已被破壞。這裏報告:http://code.djangoproject.com/ticket/11569

我強烈建議堅持memcache後端。

0

核心/緩存/後端代碼/ db.py的部分內容。出於某種原因,cursor.fetchone()在實際存在一個時返回0行。

如果你不能在這裏調試器中斷,我會把跟蹤語句放入源代碼中,以確認這實際上正在發生。

0

我通過創建自定義緩存後端,覆蓋_base_set()函數並像這樣更改INSERT INTO語句來解決此問題。這種SQL技巧可以防止在cache_key已經存在的情況下發生INSERT。

cursor.execute("INSERT INTO %s (cache_key, value, expires) SELECT %%s, %%s, %%s WHERE NOT EXISTS (SELECT 1 FROM %s WHERE cache_key = %%s)" % (table, table), 
       [key, encoded, connections[db].ops.value_to_db_datetime(exp), key])