2014-05-23 56 views
0

在使用LiveServerTestCase和Selenium测试Django/Postgres应用程序时,我看到间歇性死锁问题。 LiveServerTestCase继承自TransactionTestCase,因此在每次测试运行后,所有数据库表都会被截断。但有时该截断导致死锁,因为其中一个表被未解析的Postgres事务锁定。我可以看到,因为此查询返回一行:Django LiveServerTestCase,Selenium和Postgres间歇性死锁

select * from pg_stat_activity 
     where datname='test' and current_query='<IDLE> in transaction'; 

因此,我的应用程序中的某些活动必须创建未解决的事务。我已经梳理了测试,以确保他们在退出之前等待任何更新完成并确信不是这样。

望着Postgres的日志,我经常看到这两行,没有相应的COMMITROLLBACK

SHOW default_transaction_isolation 
BEGIN 

我怀疑这是造成僵局。任何想法可能会发布此SQL或如何禁用它?这是Django 1.5。

+0

你没有提到任何提到死锁的东西。您听明白了一个僵局是什么(它不只是那东西已经被锁定) –

+0

如果我开始两个'psql',并在第一次启动事务,但不作任何锁定,并与第二个检查,第二个显示第一个是“闲置交易”。所以在我看来,“闲置交易”本身并不是很多。我会看看'pg_locks',并检查相关的进程ID是否打开了锁。应该有一个'virtualxid'类型的锁,它锁定在事务本身上。其他锁可能会出现问题。 – Louis

回答

2

这个死锁的根本原因是Django 1.5的自动提交行为。默认情况下,Django 1.5以一个打开的事务运行,如果您执行UPDATEINSERT,则该事务仅由COMMIT关闭。 “阅读”操作(SELECT)导致我上面提到的无与伦比的BEGIN陈述。看起来如果SELECT发生在测试结束TRUNCATE之前,就会发生死锁。为了避免死锁,只有在所有请求都完成后,测试才能退出,即使这些请求不会导致数据库写入。如果Ajax调用在更新后异步更新页面的部分,这可能会非常棘手。

更好的解决方案是使用Django 1.6,其中atomic()是唯一的(非不推荐)事务创建原语。它不会为读取操作打开事务,并且不会留下悬挂的语句BEGIN。测试可以遵循在“写入”请求待处理时不退出的常识方法。