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

k4ymrczo  于 2022-12-27  发布在  Go
关注(0)|答案(1)|浏览(134)

我已经设置了Django在它们自己的线程中运行一些循环任务,我注意到它们总是留下未完成的数据库连接进程(pgsql“Idle In Transaction”)。
我查看了Postgres日志,发现事务没有完成(没有ROLLBACK),我尝试在我的函数上使用各种事务装饰器,但没有成功。
我切换到手动事务管理并手动进行回滚,这起到了作用,但仍然让进程处于“空闲”状态。
于是我调用connection.close(),一切都好了。
但我想知道,为什么Django的典型事务和连接管理不能用于这些从主Django线程派生的线程化任务?

a11xaf1n

a11xaf1n1#

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

    • 交易记录**

Django默认的自动提交行为仍然适用于我的线程化函数,不过Django文档中有这样的描述:
只要你执行了一个需要写入数据库的操作,Django就会生成INSERT/UPDATE/DELETE语句,然后执行COMMIT,没有隐式的ROLLBACK。
最后一句话很直白,它不会发出ROLLBACK命令,除非Django中有东西设置了dirty标志。因为我的函数只执行SELECT语句,所以它不会设置dirty标志,也不会触发COMMIT。
这违背了PostgreSQL认为事务需要ROLLBACK的事实,因为Django发布了一个时区的SET命令。在查看日志时,我把自己弄糊涂了,因为我一直看到这些ROLLBACK语句,并假设Django的事务管理是源代码。结果不是,这没关系。

    • 连接**

连接管理是一个棘手的问题,Django使用signals.request_finished.connect(close_connection)来关闭它通常使用的数据库连接,因为Django中通常不会发生任何不涉及请求的事情,所以你认为这种行为是理所当然的。
然而,在我的例子中,没有请求是因为作业被调度了。没有请求意味着没有信号。没有信号意味着数据库连接从未关闭过。
回到事务,结果是在没有对事务管理进行任何更改的情况下简单地发出对connection.close()的调用会在PostgreSQL日志中发出我一直在寻找的ROLLBACK语句。

    • 解决方案**

解决方案是允许正常的Django事务管理照常进行,并通过以下三种方式之一关闭连接:
1.编写一个装饰器来关闭连接并在其中 Package 必要的函数。
1.钩住现有的请求信号,让Django关闭连接。
1.在功能结束时手动关闭连接。
这三个中的任何一个都会(而且确实)起作用。

相关问题