我的Django网站最近开始从我的缓存代码中抛出错误,我无法弄清楚为什么......
我打电话:
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。有什么想法吗?
答案 0 :(得分:4)
这是一场典型的比赛。它检查您插入的密钥是否存在;如果没有,它会进行插入,但是其他人可以在计数和插入之间插入密钥。交易不会阻止这种情况。
代码似乎期望这样并尝试处理它,但是当我查看处理这种情况的代码时,我可以立即看到它被破坏了。在此报告:http://code.djangoproject.com/ticket/11569
我强烈建议坚持使用memcache后端。
答案 1 :(得分:0)
core / cache / backend / db.py中的代码部分读取:
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而不是UPDATE,因为 result 的计算结果为false。出于某种原因,当实际存在一行时,cursor.fetchone()返回0行。
如果你不能在这里打破调试器,我会将跟踪语句放入源代码中以确认实际发生这种情况。
答案 2 :(得分: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])