python - 线程化的 Django 任务不会自动处理事务或数据库连接?

标签 python database django multithreading transactions

我已将 Django 设置为在它们自己的线程中运行一些重复性任务,我注意到它们总是留下未完成的数据库连接进程(pgsql“Idle In Transaction”)。

我查看了 Postgres 日志,发现事务没有完成(没有 ROLLBACK)。我尝试在我的函数上使用各种事务装饰器,但没有成功。

我切换到手动事务管理并手动进行回滚,这有效,但仍将进程保持为“空闲”。

然后我调用了connection.close(),一切都很好。

但我想知道,为什么 Django 的典型事务和连接管理不适用于从主 Django 线程产生的这些线程任务?

最佳答案

经过数周的测试和阅读 Django 源代码,我找到了自己问题的答案:

交易

Django 的默认自动提交行为仍然适用于我的线程函数。但是,它在 Django 文档中声明:

As soon as you perform an action that needs to write to the database, Django produces the INSERT/UPDATE/DELETE statements and then does the COMMIT. There’s no implicit ROLLBACK.

最后一句非常直白。除非 Django 中的某些东西设置了脏标志,否则它不会发出 ROLLBACK 命令。由于我的函数只执行 SELECT 语句,它从未设置脏标志,也没有触发 COMMIT。

这与 PostgreSQL 认为事务需要 ROLLBACK 的事实背道而驰,因为 Django 为时区发出了 SET 命令。在查看日志时,我放弃了自己,因为我一直看到这些 ROLLBACK 语句,并认为 Django 的事务管理是源。事实证明不是,没关系。

连接

连接管理是事情变得棘手的地方。原来 Django 使用 signals.request_finished.connect(close_connection) 来关闭它通常使用的数据库连接。由于在 Django 中通常不会发生不涉及请求的事情,因此您认为这种行为是理所当然的。

但在我的情况下,没有请求,因为作业已安排。没有请求就意味着没有信号。无信号表示数据库连接从未关闭。

回到事务,事实证明,在没有对事务管理进行任何更改的情况下简单地调用 connection.close() 会在我的 PostgreSQL 日志中发出 ROLLBACK 语句我一直在寻找。

解决方案

解决方案是让正常的 Django 事务管理正常进行,并简单地关闭以下三种方式之一的连接:

  1. 编写一个装饰器来关闭连接并在其中包装必要的功能。
  2. Hook 现有的请求信号以让 Django 关闭连接。
  3. 在函数结束时手动关闭连接。

这三个中的任何一个都会(并且确实)起作用。

这让我发疯了好几个星期。我希望这对将来的其他人有所帮助!

关于python - 线程化的 Django 任务不会自动处理事务或数据库连接?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1303654/

相关文章:

python - 具有不同类型问题的 Django 测验应用程序

python - 将 ord() 与 ascii 选项卡、输入等一起使用

python - 将段落分割成句子

MySQL 从最后 N 组中选择所有行

html - 如何在单独的页面上存储部分表单数据?

mysql - 如何从 Django 数据库显示 Mysql 中的所有现有记录?

Python:快速范围求和()

python - Pascal DLL 没有函数

ios - 如何将一组图像保存到 firebase 数据库中?

python - 协议(protocol)错误,得到 "H"作为回复类型字节