Django cache.set()导致重复键错误

时间:2009-07-27 17:31:09

标签: python django postgresql caching

我的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。有什么想法吗?

3 个答案:

答案 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])