在多个Python模块中共享数据库连接的正确方法

14 投票
3 回答
20388 浏览
提问于 2025-04-16 22:17

我想在多个Python模块之间共享一个数据库对象。

举个相关的例子,我创建了一个叫global.py的文件:

DOCS_ROOT="c:\docs" ## as an example
SOLR_BASE="http://localhost:8636/solr/"

任何需要这个对象的其他模块都可以这样做:

from globl import DOCS_ROOT

抛开这个例子,我想做同样的事情,分享数据库连接对象,让它们在多个模块之间共享

import MySQLdb
conn = MySQLdb.connect (host="localhost"...)
cursor = conn.cursor()

我在解释器上试过这个:

from globl import cursor

看起来是可以的。但我怀疑这会导致每次从这个模块导入时,都会执行同一个模块。所以这样做算是正确的吗?

3 个回答

1

我觉得Daniel已经回答了这个问题,不过我想对你想分享的游标对象再补充几句。

一般来说,直接分享游标对象并不是个好主意。当然,这要看你的程序具体是做什么的,但作为一个通用的解决方案,我建议你把这个游标对象隐藏在一个“工厂”里面,这个工厂负责生成游标。简单来说,你可以创建一个方法,比如cursor()或者get_cursor(),而不是把游标做成一个全局变量。这样做的主要好处(但不是唯一的好处)是你可以在这个“工厂”后面隐藏更复杂的逻辑——比如连接池、在连接断开时自动重连等等。即使你现在不需要这些功能,如果你现在开始使用这种方法,以后添加这些功能也会变得非常简单,而目前你可以把这个函数的实现保持得很简单,比如return _cursor

对了,模块本身还是只会被导入一次。

50

即使导入的代码不会多次运行,这种做法也绝对不对。

你应该把获取连接或游标的过程放在一个函数里。然后你可以用一种叫做 单例模式对象池模式 来实现这个函数。

所以大概是这样的:

db.py:

_connection = None

def get_connection():
    global _connection
    if not _connection:
        _connection = MySQLdb.connect(host="localhost"...)
    return _connection

# List of stuff accessible to importers of this module. Just in case
__all__ = [ 'getConnection' ]

## Edit: actually you can still refer to db._connection
##         if you know that's the name of the variable.
## It's just left out from enumeration if you inspect the module

someothermodule.py:

import db
conn = db.get_connection() # This will always return the same object

顺便说一下,根据你正在做的事情,分享你的连接对象可能不是个好主意,可能每次需要时创建一个新的连接会更好。

但这就是你想写一个 get_connection() 方法的原因,它可以帮助你在代码的其他部分避免这些问题。

5

你想错了。代码只会执行一次——后面的导入只是通过 sys.modules 来引用这个模块,而不会重新运行它。

(注意,只要你总是用相同的路径来导入模块,这种情况就成立。如果你在一个地方用 from globl import cursor,而在另一个地方用 from my.fullyqualified.project.global import cursor,那么你可能会发现代码被重新执行了。)

补充说明:正如 S.Lott 在评论中提到的,这是一种处理全局对象的很好方法。

撰写回答