SQLAlchemy连接MySQL触发get_default_isolation_level下KeyError:0报错咨询
问题根因说明
- 该问题和Python 3.9.6版本没有兼容性关系,你可以正常使用该Python版本。
- 该问题和MySQL服务端版本有一定关联,更直接的原因是你使用的MySQL数据库驱动配置了返回字典格式的查询结果,而你当前使用的SQLAlchemy 1.4.23版本没有兼容这种情况,默认按元组下标访问结果,所以触发了
KeyError。 - 你之前尝试手动指定事务隔离级别不生效,是因为
get_isolation_level方法是SQLAlchemy在首次建立连接时自动触发的初始化逻辑,用于检测服务端的默认配置,不管你有没有手动指定隔离级别都会执行,所以无法跳过该调用。
无侵入解决方案
你可以从三个方案中选择适合自己业务场景的,不需要修改第三方依赖源码:
- 方案1:升级SQLAlchemy版本
这个问题是SQLAlchemy 1.4.23的已知bug,后续的1.4分支小版本以及2.x全版本都已经修复了该兼容问题,你可以直接升级SQLAlchemy到更高版本即可,不需要修改任何业务代码,执行命令pip install --upgrade sqlalchemy==1.4.49(1.4的最新稳定版)即可解决。 - 方案2:修改驱动游标返回格式
如果你暂时不能升级SQLAlchemy版本,可以在创建数据库引擎时指定驱动的游标类型为默认的元组返回格式,不要使用字典游标,示例代码如下:
改完之后查询结果会以元组格式返回,SQLAlchemy的原生代码# 以pymysql驱动为例 import pymysql from sqlalchemy import create_engine engine = create_engine( "mysql+pymysql://你的数据库连接串", connect_args={ "cursorclass": pymysql.cursors.Cursor # 不要使用DictCursor } )val = row[0]就可以正常访问。 - 方案3:运行时动态替换问题方法
如果你既要保留字典游标,又不能升级SQLAlchemy版本,可以在业务代码初始化数据库之前,动态替换SQLAlchemy MySQL方言的get_isolation_level方法,不需要修改依赖源码,示例代码如下:from sqlalchemy.dialects.mysql.base import MySQLDialect def patched_get_isolation_level(self, connection): cursor = connection.cursor() cursor.execute("SELECT @@transaction_isolation") row = cursor.fetchone() cursor.close() # 兼容字典和元组两种返回格式 if isinstance(row, dict): val = row['@@transaction_isolation'] else: val = row[0] return val.replace("-", " ") # 替换原生方法 MySQLDialect.get_isolation_level = patched_get_isolation_level
内容的提问来源于stack exchange,提问作者Jimmy Hurd
相关产品推荐
相关产品推荐

