所以我使用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 /秒或更短)调用时,结果将按预期返回,但是当并发调用时,偶尔会返回None。我尝试过多种方式来编写这个查询&amp;方法。
一些观察结果:
需要注意的条件:
这是一份副本&amp;粘贴的输出返回无:
DBSELECT.get_feed_cache: None
sql: SELECT feed_cache FROM feed_cache WHERE feed_id=5 AND localtimestamp < expire_date;
那就是它,我不确定发生了什么。也许我犯了一些非常愚蠢的错误,我只是没注意到它! 我目前的猜测是它与psycopg2有关,也许它与游标之间的缓存结果有关。如果游标共享缓存并且查询几乎同时发生,则第一个游标可能会获取结果,第二个游标看到存在相同查询的缓存,因此它不执行,然后是第一个游标关闭并删除缓存,第二个光标尝试获取一个现在为空/无缓存。 *
也就是说,psycopg2声明它对于只读查询是线程安全的,所以除非我错过了解释它们的线程安全实现,否则不应该这样。
感谢您的时间!
*为get_feed_cache添加一个线程锁,在创建游标之前获取并在返回之前释放,我仍然偶尔得到一个无结果
答案 0 :(得分:1)
我认为这可能与localtimestamp
或current_timestamp
返回的时间戳在事务开始时被修复的事实有关,而不是在运行语句时。 psycopg在某种程度上管理你背后的交易。所以你可能会得到一个稍微旧的时间戳。
您可以通过在服务器中设置log_statement = all
来调试此操作,然后观察相对于您的查询执行BEGIN
语句的时间。
您可能希望使用clock_timestamp()
这样的函数,每个事务更新一次。请参阅http://www.postgresql.org/docs/current/static/functions-datetime.html。