在自定义线程脚本中使用Django DB连接

时间:2016-04-17 21:10:31

标签: python django multithreading

关于django db连接线程安全有很多问题,但它们似乎都在询问默认请求线程。

如果我在线程中编写使用数据库连接的自定义脚本,该怎么办?

from django.db import connections
import threading

class Transform(object):
    def transform_data(self, listing):
        cursor = self.connection.cursor()
        cursor.execute('SELECT ... WHERE id = %s', listing.id)
        data  = cursor.fetchall()
        ...

    def run(self):
        connection = self.connections['legacy']
        for listing in listings:
            threading.Thread(target=self.transform_data, args=[listing])

transform_data线程中的数据在游标结果方面与其他线程的混淆程度有多安全?

2 个答案:

答案 0 :(得分:1)

理想情况下,每个线程都应该使用自己的连接。如果在执行transform_data中的select查询时执行此操作,则实际上是在该时间点获取数据的快照。您可以检索行而不必担心其他线程更新或删除它们,前提是其他线程有自己的连接。

如果所有线程共享相同的连接,那么究竟发生的情况非常依赖于您正在使用的数据库和事务隔离级别

答案 1 :(得分:0)

connections对象中的每个项都返回与该数据库的线程本地连接。默认情况下,这些连接不能在线程之间共享;尝试这样做会导致DatabaseError

始终在执行查询的线程中使用connections[alias] 。永远不要访问父线程中的connections[alias]并将对象传递给子线程。这将确保您使用的每个连接对象都是当前线程的本地对象,从而避免任何线程问题。

要修复代码并使其成为线程安全的,您可以像这样更改它:

from django.db import connections
import threading

class Transform(object):
    def transform_data(self, listing):
        # Access the database connection on the global `connections` object
        # from within the child thread.
        cursor = connections['legacy'].cursor()
        cursor.execute('SELECT ... WHERE id = %s', listing.id)
        data  = cursor.fetchall()
        ...

    def run(self):
        for listing in listings:
            threading.Thread(target=self.transform_data, args=[listing])