在使用LiveServerTestCase和Selenium测试Django/Postgres应用程序时,我看到了间歇性的死锁问题。LiveServerTestCase继承自TransactionTestCase,因此每次测试运行后都会截断所有DB表。但有时这种截断会导致死锁,因为其中一个表被未解析的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。

最佳答案

这个死锁的根本原因是Django 1.5的autocommit行为。默认情况下,Django 1.5与打开的事务一起运行,只有在执行COMMITUPDATE操作时,该事务才会由INSERT关闭。”阅读“操作(SELECT)导致上面提到的不匹配的BEGIN语句。如果SELECT在测试TRUNCATE结束之前发生,则会出现死锁。为了避免死锁,测试必须在所有请求完成之后才能退出,即使请求不会导致DB写入。如果Ajax调用在更新后异步更新页面的某些部分,那么这可能会很棘手。
一个更好的解决方案是使用Django 1.6,其中atomic()是唯一的(非弃用的)事务创建原语。它不会为读取操作打开事务,也不会留下挂起的BEGIN语句。测试可以遵循“退出”的常识性方法,而“写入”请求则悬而未决。

09-27 00:33
查看更多