惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

小众软件
小众软件
A
About on SuperTechFans
博客园 - Franky
Engineering at Meta
Engineering at Meta
Recent Announcements
Recent Announcements
云风的 BLOG
云风的 BLOG
B
Blog
Microsoft Security Blog
Microsoft Security Blog
L
LangChain Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
U
Unit 42
Martin Fowler
Martin Fowler
Y
Y Combinator Blog
Stack Overflow Blog
Stack Overflow Blog
博客园 - 叶小钗
Vercel News
Vercel News
Apple Machine Learning Research
Apple Machine Learning Research
The Cloudflare Blog
Last Week in AI
Last Week in AI
腾讯CDC
Microsoft Azure Blog
Microsoft Azure Blog
爱范儿
爱范儿
V
V2EX
G
Google Developers Blog

博客园 - 清虚真人

[原]跟我学silverlight系列教程[1]—wpf/silverlight体系架构和运行机制 [原]跟我学silverlight系列教程 sql2005 数据库没有完全关闭,无法重新生成日志 IIS中网站出错 javascript获取滚动条位置 - 清虚真人 - 博客园 .Net framework [转载]My97DatePicker在Frame中无法打开站点 输出datagrid的内容到excel - 清虚真人 - 博客园 sql select的时候按特定的顺序排序 vs2008 安装Silverlight tools遇到的崩溃问题。。。 关于.NET中的Server push技术 .net 几种序列化类的比较 asp.net ajax实现(—):Jquery+Json WPF中BitMapEffect的性能问题 我写的PageDataSurce分页的 asp.net页面执行机制 关于服务器端控件的attributes属性的奇怪问题 关于使用javascript+asp.net实现多文件上传的若干问题 正则表达式相关教程
关于flask-sqlalchemy的用法研究
清虚真人 · 2019-12-10 · via 博客园 - 清虚真人

最近使用到flask的sqlalchemy,因为flask对sqlalchemy做了一些封装,加上自己本身对sqlalchemy也不熟悉,用法上走了很多弯路。

因为没时间去研究sqlalchemy的源码,所以只能简单的测试下用法。

1、flask-sqlalchemy是线程安全的

  具体可以参考文章 https://blog.csdn.net/luffyser/article/details/89380186

2、每次查询完以后,记得commit,不然会占用连接池

  我在本地做了个简单的测试,如果单次查询请求完,不commit的话,连续请求几次,再发起request就没有响应了,推测是数据库连接池没释放,被占用。导致请求数据库挂起,从而导致没有response。

      每次请求完,直接commit,可以解决此问题。  

    def queryLast(cls):
        try:
            ret = db.session.query(cls).order_by(cls.version.desc()).first()
       #db.session.expunge(ret) db.session.commit() except: db.session.rollback() ret = None return ret

3、但是,如果Commit后,查询结果可能会从缓存中清掉,如果再使用查询结果的对象,还会再次建立连接查询。所以还会出现上述连接池耗尽的问题。

   从下图标黄的日志可以看出,commit后,使用返回的查询结果时,又执行了一次查询任务,并返回结果,my god!

2019-12-10 12:31:21,650 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2019-12-10 12:31:21,651 INFO sqlalchemy.engine.base.Engine SELECT appversion.id AS appversion_id, appversion.version AS appversion_version, appversion.`appUrl` AS `appversion_appUrl`, appversion.des AS appversion_des, appversion.`createTime` AS `appversion_createTime`, appversion.`lastModiftyTime` AS `appversion_lastModiftyTime`, appversion.type AS appversion_type 
FROM appversion ORDER BY appversion.version DESC 
 LIMIT %s
2019-12-10 12:31:21,651 INFO sqlalchemy.engine.base.Engine (1,)
2019-12-10 12:31:21,661 INFO sqlalchemy.engine.base.Engine COMMIT
2019-12-10 12:31:21,680 INFO sqlalchemy.engine.base.Engine BEGIN (implicit) 2019-12-10 12:31:21,681 INFO sqlalchemy.engine.base.Engine SELECT appversion.id AS appversion_id, appversion.version AS appversion_version, appversion.`appUrl` AS `appversion_appUrl`, appversion.des AS appversion_des, appversion.`createTime` AS `appversion_createTime`, appversion.`lastModiftyTime` AS `appversion_lastModiftyTime`, appversion.type AS appversion_type FROM appversion WHERE appversion.id = %s 2019-12-10 12:31:21,681 INFO sqlalchemy.engine.base.Engine (1,)

4、但有时候(可能是时间略长些)commit后,再使用查询结果的对象,可能会出现报错:Instance <User at 0x32768d0> is not bound to a Session   

  此种情况可能是因为绑定的session已经被回收,导致无法再进行查询,所以出错。

5、综上所述,为安全起见,需要在查询结果后,加上 db.session.expunge(ret),断开查询结果与session的关系。让它成为一个本地实体,不会从缓存中清除,使用时候,就不会再查询。

6、但测试时候发现一个奇怪的问题,另外一个获取user的接口,和上面的代码几乎没什么区别,居然会自动rollback,这个让我百思不得其解。

  我的逻辑是取到查询结果(即用户)后,判断用户的状态字段是否为1,如果为1,就修改用户属性,然后commit,如果不是1,就不做操作,也没有调用rollback。

  但是我测试时候发现,如果不是1的时候,它会自动rollback。

        或许这是sqlalchemy的高级功能?

7、总结:

  1、sqlalchemy的对象实体(model),和session建立了联系,你get、set这些model的时候,就算已经commit,也会重新自动和数据库建立连接(get的时候会重新select、set的时候会重新建立连接,等待你提交,如果你不提交,这个连接一直存在,最终会耗尽。),所以要谨慎使用model的字段,除非你确实明白自己在做什么,会发生什么。

  2、使用db.session.expunge会切断实体和session的关系。这个是个不错的用法。

  3、但我还是强烈建议自己再搞一套model,来做业务层逻辑。sqlalchemy的对象实体仅用来做数据库的操作。这样会避免很多时候,连接不小心没释放的坑。