Python 如何使用SQLAlchemy关闭和重新连接以避免事务超时中的空闲
我编写了一个Python应用程序,它使用SQLAlchemy连接到Postgres DB。Python 如何使用SQLAlchemy关闭和重新连接以避免事务超时中的空闲,python,postgresql,sqlalchemy,Python,Postgresql,Sqlalchemy,我编写了一个Python应用程序,它使用SQLAlchemy连接到Postgres DB。引擎和会话在db.py engine = create_engine(URL(**settings.DATABASE)) session = scoped_session(sessionmaker(bind=engine)) from app.db import engine, session def get_door_ids(): result = session.query(Controll
引擎
和会话
在db.py
engine = create_engine(URL(**settings.DATABASE))
session = scoped_session(sessionmaker(bind=engine))
from app.db import engine, session
def get_door_ids():
result = session.query(ControllerDetail.door_id).distinct().all()
ids = [c[0] for c in result]
return ids
def get_last_health_cd(door_id):
result = session.query(ControllerDetail.door_health_cd).filter(ControllerDetail.door_id == door_id).order_by(ControllerDetail.etl_insert_ts.desc()).first()
return result[0]
大多数db操作都在service.py
中,它从db.py
engine = create_engine(URL(**settings.DATABASE))
session = scoped_session(sessionmaker(bind=engine))
from app.db import engine, session
def get_door_ids():
result = session.query(ControllerDetail.door_id).distinct().all()
ids = [c[0] for c in result]
return ids
def get_last_health_cd(door_id):
result = session.query(ControllerDetail.door_health_cd).filter(ControllerDetail.door_id == door_id).order_by(ControllerDetail.etl_insert_ts.desc()).first()
return result[0]
现在一切都很好,但问题是我需要每隔几分钟重复运行相同的程序。因此,我的主模块中有以下代码:
try:
while True:
run_task()
time.sleep(120)
except KeyboardInterrupt:
print('Manual break by user')
DB每分钟超时一次空闲连接。因此,每次进程休眠超过1分钟时,我都会出错
psycopg2.InternalError: terminating connection due to idle-in-transaction timeout
SSL connection has been closed unexpectedly
我想知道是否有办法在时间之后关闭会话并重新打开它。sleep(120)
这样它就不会超时。可能在主模块中,我从db
导入session
作为全局变量,并以某种方式将其传递给服务中的方法。我该怎么做?我不能从main
导入services
中的session
,而不能从db
导入,因为main
从services
导入功能
增加超时时间
create_引擎(URL(**settings.DATABASE),connect_args={'connect_timeout':10})
出现错误时创建新会话
您可以通过session.close()
首先,您应该通过提交/回滚及时结束事务。会话还将隐式回滚。如果是作用域会话,将关闭该会话(并从注册表中删除该会话)。总而言之,这是一本很好的读物
一些人可能会感到惊讶的是,会话
会在您开始与数据库通信时立即启动一个新事务。然后,您的工作就是结束该交易。如果不了解run_task()
的实际作用,很难说哪个部分应该处理会话的生存期,但可以肯定地说,如果任务每隔几分钟运行一次,您就不应该让事务挂起那么长时间。那么客户端的超时设置会覆盖服务器的设置吗?由于会话是在db.py
中创建的,然后导入到其他模块中,因此无法轻松创建/关闭会话,也无法让所有方法都像以前一样使用与服务器设置相关的相同会话。您可以根据需要增加数据库由我们的DBA管理的时间。超时是他不愿改变的事情之一。为了关闭并重新连接主模块中的会话
,我必须将其作为全局文件从db
导入,并将其传递给服务
中的方法。我该怎么做呢?我在运行任务()之前创建了作用域会话
,之后将其关闭。现在,session
是run\u任务(session)
的一个参数。因此,所有其他函数也将会话
作为其参数。不确定将session
作为这些查询函数的参数是否是常见的做法,但它在使用线程局部作用域会话时工作。行有点模糊,因为卖点之一是您不需要显式地传递会话(尽管这没有错),并且如果您的任务(或您所拥有的)由工作线程处理。使用作用域_会话
可以很容易地将会话的生命周期与工作线程的生命周期联系起来。当您说您曾经在run_task()
之后关闭作用域会话时,请执行循环调用run_task()
它在同一个线程中实际运行的是什么?如果不是,您创建了一个会话,工作线程又创建了一个。我没有使用线程。这是一个警报引擎,需要每两分钟运行一次,并轮询数据库中的异常情况。run\u task
所做的只是查询和发送电子邮件。啊,在这种情况下,您不需要一个scoped_session
。只需从sessionmaker()
获取一个普通的session
旧实例就可以了,传递它是一个很好的模式;至少它使测试更容易,并提高了可重用性。