转自:https://pdf-lib.org/Home/Details/7406

在更改 SQLAlchemy Session 从每次请求都创建到共享同一个 Session 之后遇到了如下问题:

StatementError: (sqlalchemy.exc.InvalidRequestError) Can’t reconnect until invalid transaction is rolled back [SQL: ]

或者是

raised unexpected: OperationalError(“(_mysql_exceptions.OperationalError) (2006, ‘MySQL server has gone away’)”,)

错误是 SQLAlchemy 抛出。原因是你从 pool 拿的 connection 没有以 session.commit 或 session.rollback 或者 session.close 放回 pool 里。这时 connection 的 transaction 没有完结(rollback or commit)。 而不知什么原因(recyle 了,timeout 了)你的 connection 又死掉了,你的 sqlalchemy 尝试重新连接。由于 transaction 还没完结,无法重连。

正确用法是确保 session 在使用完成后用 session.close, session.commit 或者 session.rollback 把连接还回 pool。

SQLAlchemy 数据库连接池使用

sessions 和 connections 不是相同的东西, session 使用连接来操作数据库,一旦任务完成 session 会将数据库 connection 交还给 pool。

在使用 create_engine 创建引擎时,如果默认不指定连接池设置的话,一般情况下,SQLAlchemy 会使用一个 QueuePool 绑定在新创建的引擎上。并附上合适的连接池参数。

在以默认的方法 create_engine 时(如下),就会创建一个带连接池的引擎。

engine = create_engine('mysql+mysqldb://root:password@127.0.0.1:3306/dbname')

在这种情况下,当你使用了 session 后就算显式地调用 session.close(),也不能把连接关闭。连接会由 QueuePool 连接池进行管理并复用。

这种特性在一般情况下并不会有问题,不过当数据库服务器因为一些原因进行了重启的话。最初保持的数据库连接就失效了。随后进行的 session.query() 等方法就会抛出异常导致程序出错。

如果想禁用 SQLAlchemy 提供的数据库连接池,只需要在调用 create_engine 是指定连接池为 NullPool,SQLAlchemy 就会在执行 session.close() 后立刻断开数据库连接。当然,如果 session 对象被析构但是没有被调用 session.close(),则数据库连接不会被断开,直到程序终止。

下面的代码就可以避免 SQLAlchemy 使用连接池:

#!/usr/bin/env python
#-*- coding: utf-8 -*-from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.pool import NullPoolengine = create_engine('mysql+mysqldb://root:password@127.0.0.1:3306/dbname', poolclass=NullPool)
Session = sessionmaker(bind=engine)
session = Session()
usr_obj_list = session.query(UsrObj).all()
print usr_obj_list[0].id
session.close()

create_engine() 函数和连接池相关的参数有:

  • -pool_recycle, 默认为 -1, 推荐设置为 7200, 即如果 connection 空闲了 7200 秒,自动重新获取,以防止 connection 被 db server 关闭。
  • -pool_size=5, 连接数大小,默认为 5,正式环境该数值太小,需根据实际情况调大
  • -max_overflow=10, 超出 pool_size 后可允许的最大连接数,默认为 10, 这 10 个连接在使用过后,不放在 pool 中,而是被真正关闭的。
  • -pool_timeout=30, 获取连接的超时阈值,默认为 30 秒

直接只用 create_engine 时,就会创建一个带连接池的引擎

engine = create_engine('postgresql://postgres@127.0.0.1/dbname')

当使用 session 后就显示地调用 session.close(),也不能把连接关闭,连接由 QueuePool 连接池管理并复用。

引发问题

当数据库重启,最初保持的连接就会失败,随后进行 session.query() 就会失败抛出异常 mysql 数据 ,interactive_timeout 等参数处理连接的空闲时间超过(配置时间),断开

何时定义 session,何时提交,何时关闭

基本

  • 通常来说,将 session 的生命周期和访问操作数据库的方法对象隔离和独立。
  • 确保 transaction 有非常清晰的开始和结束,保持 transaction 简短,也就意味着让 transaction 能在一系列操作之后终止,而不是一直开放着。

    from contextlib import contextmanager

    @contextmanager def session_scope(): “"”Provide a transactional scope around a series of operations.””” session = Session() try: yield session session.commit() except: session.rollback() raise finally: session.close()

是否线程安全

Session 不是为了线程安全而设计的,因此确保只在同一个线程中使用。

如果实际上有多个线程参与同一任务,那么您考虑在这些线程之间共享 Session 及其对象;但是在这种极不寻常的情况下,应用程序需要确保实现正确的 locking scheme,以便不会同时访问 Session 或其状态。处理这种情况的一种更常见的方法是为每个并发线程维护一个 Session,而是将对象从一个 Session 复制到另一个 Session,通常使用 Session.merge() 方法将对象的状态复制到本地的新对象中。

scoped session

想要线程安全时使用 scoped_session() ,文档解释

the scoped_session() function is provided which produces a thread-managed registry of Session objects. It is commonly used in web applications so that a single global variable can be used to safely represent transactional sessions with sets of objects, localized to a single thread.

using transactional=False is one solution, but a better one is to simply rollback(), commit(), or close() the Session when operations are complete - transactional mode (which is called “autocommit=False” in 0.5) has the advantage that a series of select operations will all share the same isolated transactional context..this can be more or less important depending on the isolation mode in effect and the kind of application.

DBAPI has no implicit “autocommit” mode so there is always a transaction implicitly in progress when queries are made.

This would be a fairly late answer. This is what happens: While using the session, a sqlalchemy Error is raised (anything which would also throw an error when be used as pure SQL: syntax errors, unique constraints, key collisions etc.).

You would have to find this error, wrap it into a try/except-block and perform a session.rollback().

After this you can reinstate your session.

flush 和 commit 区别

  • flush 预提交,等于提交到数据库内存,还未写入数据库文件;
  • commit 就是把内存里面的东西直接写入,可以提供查询了;

SQLAlchemy session 使用问题相关推荐

  1. 【Python】SQLAlchemy:session何时commit,何时close?

    SQLAlchemy:session何时commit,何时close? 参考阅读:SQLAlchemy - 官方文档 官方文档说明了关于什么是session,以及如何创建session.如何使用ses ...

  2. sqlalchemy下连接MYSQL出现的错误:This session is in ‘prepared‘ state; no further SQL can be emitted ...

    InvalidRequestError: This session is in 'prepared' state; no further SQL can be emitted within this ...

  3. SQLAlchemy中的Django风格的数据库路由器

    Updated August, 2014 – the approach here really won't work very well if you are using transactions! ...

  4. SQLAlchemy学习教程

    简介 简单来说就是讲类和对象转换成SQL,然后使用数据API执行SQL并获取执行结果! 最容易入门的情况,如果有一张用户表,这个表里面是记录的所有用户的信息,包含名字.年龄.性别.这是数据表的基本情况 ...

  5. python之蓝图blueprint浅析

    目录 背景 一.python中的蓝图 二.创建蓝图 三.蓝图的运行机制 四.蓝图的url前缀 五.注册蓝图中的静态文件的相关路由 六.设置蓝图中模版的目录 七.调整session配置 背景 由于我们现 ...

  6. Python 中的面向对象没有意义

    编译 | 弯月   责编 | 张文 出品 | CSDN(ID:CSDNnews) 许多人都在抨击面向对象,虽然我不认为他有什么问题,但我觉得至少在 Python 中没必要. 近来,许多人都在抨击面向对 ...

  7. Flask入门到放弃(四)—— 数据库

    转载请在文章开头附上原文链接地址:https://www.cnblogs.com/Sunzz/p/10979970.html 数据库操作 ORM ORM 全拼Object-Relation Mappi ...

  8. Flask之flask-session

    简介 flask-session是flask框架的session组件,由于原来flask内置session使用签名cookie保存,该组件则将支持session保存到多个地方,如: redis:保存数 ...

  9. python面向对象有什么用_Python 中的面向对象没有意义

    许多人都在抨击面向对象,虽然我不认为他有什么问题,但我觉得至少在Python 中没必要. 近来,许多人都在抨击面向对象,虽然我不认为面向对象本身有什么问题,但我觉得至少在 Python 中没这个必要. ...

  10. 理解 OpenStack 高可用(HA) (6): MySQL HA

    本系列会分析OpenStack 的高可用性(HA)概念和解决方案: (1)OpenStack 高可用方案概述 (2)Neutron L3 Agent HA - VRRP (虚拟路由冗余协议) (3)N ...

最新文章

  1. Python 调用C函数
  2. chrome java上传文件_springboot+webuploader 实现大文件切片上传,兼容IE8+,chrome等浏览器,可运行...
  3. TripleDES类 3des加密算法实现
  4. 【视频回放与课件】零基础入门AI开发
  5. 新基建时代,腾讯云数据库沿主赛道加速演进
  6. (72)FPGA模块调用(VHDL调用Verilog)
  7. 不同域名指向一个Web站点,ICP证如何设置
  8. 华为机试——整理数字字符串
  9. jQuery 的CSS选择器 中 使用变量的方法
  10. PostgreSQL 内存OOM控制策略导致数据库无法启动的诊断一例(如何有效避免oom)
  11. 关于用C#编写ActiveX控件4(转)
  12. TensorRT加速ENet
  13. 什么造就一个伟大的站点
  14. 人工智能在安全漏洞方面的应用_智慧消防平台的智慧在哪方面?
  15. 【数字信号处理】基于matlab数字信号离散序列短时傅里叶变换【含Matlab源码 1545期】
  16. python装饰器打印函数执行时间_使用python装饰器计算函数运行时间的实例
  17. 精英主义 遗传算法 matlab,遗传算法matlab程序
  18. 前端架构师的YY定义
  19. 饿了么官宣合作抖音后,美团的失意是什么?
  20. 转载 javascript联动菜单

热门文章

  1. 三星android版本4.2.2,三星 Galaxy Note (i9220) 安卓4.2.2 稳定 流畅版
  2. 计算机网络技术练习,计算机网络技术基础各章节综合练习题及答案
  3. 二、Vue实例对象及其属性
  4. 基于MATLAB串级控制系统仿真设计,毕业论文基于MATLAB的锅炉水温与流量串级控制系统的设计9喜欢就下吧(样例3)...
  5. 第七代i3核显linux驱动下载,i3-8100,装win7,集显uhd 630改版驱动完美安装
  6. 如何做好罗斯蒙特流量计管理工作
  7. 附资料:工程总承包项目管理流程图(全套)
  8. idea构建post请求_IDEA-HTTP工具
  9. 求是量子产业观察:中国量子信息产业发展迅速,初创企业成为新兴力量
  10. 仿微信朋友圈发表图片拖拽和删除功能