SQLAlchemy 运行一段时间后,出现错误BrokenPipeError 以及Parent instance <Xxx at 0x...> is not bound to a Session

错误详情 sqlalchemy.exc.DBAPIError: (cymysql.err.Error) (<class 'BrokenPipeError'>, BrokenPipeError(32, 'Broken pipe'))

嗯,最近在用sqlalchemy,程序刚开始运行时,一切增删改查都正常,一段时间(经过分析,应该是8小时后)后,会出现上述错误。

先上结论错误解决方案:

1.如果是flask项目,建议直接使用flask_sqlalchemy,即可解决该问题(有效,做过Flask的都知道,比较有意思的问题是,Flask是通过何种方式解决该问题的)

2.每次使用session后,使用session.close()

(有效性未知,程序正在运行,待我长时间运行一下该程序,记录结果,进行验证。

启动时间 2020年12月12日19:01:13  此时运行一切正常)

错误的缘由猜想

首先,该错误给出提示,

(Background on this error at: http://sqlalche.me/e/13/dbapi)

据该页面提示,错误并不是sqlalchemy本身的错误,而是数据库的错误。

进而查看mysql 的log,分析错误原因可能是mysql连接池已经关闭。

而据mysql官方文档说,连接池的有效时间是8小时。

这样,该错误的可能原因就明白了,

我们从sqlalchemy向mysql建立了一个连接,在mysql的连接池有效时间内,程序一切正常。

当到达8小时后,mysql单方面关闭连接池,而sqlalchemy依然在使用该连接池,就会导致BrokenPipeError错误。

而sqlalchemy中使用Session管理连接池。我们需要使用session.close()关闭连接池。再次调用session任务时,因为session已经关闭,sqlalchemy会重新建立一个连接。这样就解决了这个问题。

猜想的验证

一个较好的验证方式是使用try except

如下所示:

....
try:
    result = session.do_sth
    print(result)
except:
    session.close()
    result = session.do_sth
    print(result)
....

如果该代码有效,则证明上述分析都是正确的。

实际解决方案

当然,在实际代码中,不可能每处调用session,都使用try except

因此,要养成每次使用session,都主动关闭session的习惯。

衍生的问题  Parent instance <Xxx at 0x...> is not bound to a Session

如果我们定义了一个实体类,其使用relationship形成了多对一的关系。如下代码

class Test(Base):
    __tablename__ = 'test'
    id = Column(Integer, primary_key=True,autoincrement=True)
    name = Column(String(50))
    test_relationship = relationship('Test2', cascade='all, delete', passive_deletes=True)
    test_relationship_id = Column(Integer, ForeignKey("test_relationship.id", ondelete='CASCADE'))

而按照上面说的,每次调用查询后,都关闭。

def test_method():
    result = session.query(Test).first()
    session.close()
    return result.test_relationship.name

此时会报错。

sqlalchemy.orm.exc.DetachedInstanceError: Parent instance <Test at 0x217d5f13f98> is not bound to a Session; lazy load operation of attribute 'test_relationship' cannot proceed (Background on this error at: http://sqlalche.me/e/bhk3)

根据提示页面,该错误是因为sqlalchemy对于实体类默认使用的是懒加载模式,也就是在查询Test的时候,并不会直接读取Test2的信息,只有在手动调用test_relationship时,才会去数据库中查询Test2的信息。

而我们如果使用Test2信息之前,已经手动关闭了session,会导致没有办法查询。也就是他说的Test没有和session绑定(因为你自己调用了close)。

分析到这,就没明白了,我们只要在查询Test的时候,让Sqlalchemy直接load的Test2的信息,即可解决。

而实现该目标的方法,如下:

from sqlalchemy.orm import joinedload

def test_method():
    result = session.query(Test).options(joinedload('test_relathionship')).first()
    session.close()
    return result.test_relationship.name

该问题即可解决。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值