我在python中有以下功能:
def add_odm_object(obj, table_name, primary_key, unique_column):
db = create_engine('mysql+pymysql://root:@127.0.0.1/mydb')
metadata = MetaData(db)
t = Table(table_name, metadata, autoload=True)
s = t.select(t.c[unique_column] == obj[unique_column])
rs = s.execute()
r = rs.fetchone()
if not r:
i = t.insert()
i_res = i.execute(obj)
v_id = i_res.inserted_primary_key[0]
return v_id
else:
return r[primary_key]
此函数查看对象obj
是否在数据库中,如果找不到,则将其保存到数据库。现在,我有一个问题。我多次在循环中调用上面的函数。几百次之后,我收到一个错误:user root has exceeded the max_user_connections resource (current value: 30)
我尝试搜索答案,例如问题:How to close sqlalchemy connection in MySQL建议创建一个conn = db.connect()
对象,其中db
是我的查询完成后引擎并调用conn.close()
。
但是,我应该在哪里打开和关闭代码中的连接?我没有直接使用该连接,但我在代码中使用了Table()
和MetaData
函数。
答案 0 :(得分:1)
对于数据库连接,引擎是一个昂贵的创建factory。您的应用程序应该为每个数据库服务器调用create_engine()
一次。
同样,MetaData
和Table
对象描述了已知数据库中的固定架构对象。这些也是配置构造,在大多数情况下,在模块中创建一次,就像类一样。
在这种情况下,你的函数似乎想要动态加载表,这很好; MetaData对象充当registry,它具有便利功能,如果已存在,它将为您提供现有表格。
在Python函数中,特别是在循环中,为了获得最佳性能,您通常只想引用一个数据库连接。
考虑到这些因素,您的模块可能如下所示:
# module level variable. can be initialized later,
# but generally just want to create this once.
db = create_engine('mysql+pymysql://root:@127.0.0.1/mydb')
# module level MetaData collection.
metadata = MetaData()
def add_odm_object(obj, table_name, primary_key, unique_column):
with db.begin() as connection:
# will load table_name exactly once, then store it persistently
# within the above MetaData
t = Table(table_name, metadata, autoload=True, autoload_with=conn)
s = t.select(t.c[unique_column] == obj[unique_column])
rs = connection.execute(s)
r = rs.fetchone()
if not r:
i_res = connection.execute(t.insert(), some_col=obj)
v_id = i_res.inserted_primary_key[0]
return v_id
else:
return r[primary_key]