关于flask-sqlalchemy的用法研究
最近使用到flask的sqlalchemy,因为flask对sqlalchemy做了一些封装,加上自己本身对sqlalchemy也不熟悉,用法上走了很多弯路。
因为没时间去研究sqlalchemy的源码,所以只能简单的测试下用法。
1、flask-sqlalchemy是线程安全的
具体可以参考文章 https://blog.csdn.net/luffyser/article/details/89380186
2、每次查询完以后,记得commit,不然会占用连接池
我在本地做了个简单的测试,如果单次查询请求完,不commit的话,连续请求几次,再发起request就没有响应了,推测是数据库连接池没释放,被占用。导致请求数据库挂起,从而导致没有response。
每次请求完,直接commit,可以解决此问题。
1 2 3 4 5 6 7 8 9 | 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!
1 2 3 4 5 6 7 8 9 10 11 | 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的对象实体仅用来做数据库的操作。这样会避免很多时候,连接不小心没释放的坑。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· SQL Server 2025 AI相关能力初探
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库