mssql-python 驱动定义了标准的异常层级结构、常见的错误处理模式以及针对 SQL Server 和 Azure SQL 的 SQLSTATE 代码映射。
异常层次结构
mssql-python驱动遵循 DB-API 2.0(PEP 249)异常层级结构:
Exception (builtins)
├── Warning
└── Error
├── InterfaceError
└── DatabaseError
├── DataError
├── OperationalError
├── IntegrityError
├── InternalError
├── ProgrammingError
└── NotSupportedError
ConnectionStringParseError (standalone, not part of hierarchy)
异常说明
抓住最符合你情况的具体例外。 例如,捕捉 IntegrityError / 操作上的INSERT约束违规,以及ProgrammingError开发过程中的 SQLUPDATE 语法问题。 基础 Error 职业只能作为备选。
| Exception |
引发时 |
Warning |
数据库中的非致命警告。 |
Error |
所有数据库错误的基础类。 |
InterfaceError |
错误与数据库接口(驱动程序)有关,而非数据库本身。 |
DatabaseError |
数据库相关的错误。 |
DataError |
由于处理数据出现问题(除以零,值超出范围)导致的错误。 |
OperationalError |
与数据库操作相关的错误(连接丢失、内存分配、事务错误)。 |
IntegrityError |
当数据库完整性受到影响时会出现错误(如外键违规、唯一约束)。 |
InternalError |
内部数据库错误(光标无效,交易不同步)。 |
ProgrammingError |
编程错误(语法错误、找不到表格、参数数量错误)。 |
NotSupportedError |
数据库或驱动不支持此功能。 |
ConnectionStringParseError |
连接字符串语法无效或未知关键词。 |
基本错误处理
使用try-exclusion块来处理数据库错误:
import mssql_python
try:
conn = mssql_python.connect(connection_string)
cursor = conn.cursor()
cursor.execute("INSERT INTO Production.Product (Name) VALUES (%(name)s)", {"name": "Test"})
conn.commit()
except mssql_python.IntegrityError as e:
print(f"Constraint violation: {e}")
conn.rollback()
except mssql_python.ProgrammingError as e:
print(f"SQL syntax error: {e}")
except mssql_python.OperationalError as e:
print(f"Connection or operational error: {e}")
except mssql_python.Error as e:
print(f"Database error: {e}")
finally:
if 'conn' in locals():
conn.close()
通过连接的访问异常
你可以通过连接实例捕捉异常情况:
try:
cursor.execute("INVALID SQL")
except conn.ProgrammingError as e:
print(f"Caught via connection: {e}")
错误消息结构
MSSQL-Python 异常对象会暴露出来自驱动程序 Exception 基类的三个属性:
| Attribute |
Source |
描述 |
driver_error |
Python 驱动 |
由 SQLSTATE 选择的标准化英文文本从 ODBC 返回(例如, "Communication link failure", "Invalid authorization specification", "Syntax error or access violation")。 跨版本稳定;可以安全地匹配子串。 |
ddbc_error |
直接数据库连接(DDBC) |
服务器端消息,通常以 [Microsoft][SQL Server]为前缀。 格式不是稳定的合同。 |
message |
组成 |
f"Driver Error: {driver_error}; DDBC Error: {ddbc_error}"。 这就是回归的。str(exc) |
try:
cursor.execute("SELECT * FROM no_such_table;")
except mssql_python.ProgrammingError as exc:
print(exc.driver_error) # Base table or view not found
print(exc.ddbc_error) # [Microsoft][SQL Server]Invalid object name 'no_such_table'.
print(exc) # Driver Error: Base table or view not found; DDBC Error: ...
SQL Server 引擎的错误编号(例如 208 或 40501)不会作为属性暴露,也不会可靠地嵌入在任何字符串中。 通过例外子类加上 driver_error 文本来分类错误。 关于Azure SQL限速,请参见Retry logic。
SQLSTATE 分类
mssql-python 使用 ODBC 返回的 SQLSTATE 来选择 Python 异常子类和文本driver_error。 完整的 SQLSTATE →异常映射已在 exceptions.py 驱动源代码中。 下一节列出了SQL Server和Azure SQL中最常出现的SQLSTATE。
连接错误
来自 mssql_python.connect() 的 mssql_python.OperationalError连接失败与其他连接失败相同:
import mssql_python
try:
conn = mssql_python.connect(
"Server=unreachable-server.database.windows.net;"
"Database=<database>;"
"Authentication=ActiveDirectoryDefault;"
"Encrypt=yes"
)
except mssql_python.OperationalError as e:
print(f"Connection failed: {e.driver_error}")
# e.driver_error: "Client unable to establish connection"
连接字符串错误
连接字符串解析错误出现 ConnectionStringParseError:
try:
conn = mssql_python.connect("Servr=localhost;") # Typo
except mssql_python.ConnectionStringParseError as e:
print(f"Invalid connection string: {e}")
# Output: Unknown keyword 'Servr'
SQLSTATE 代码参考
SQLSTATE 代码是五字符代码,用于识别错误状况。 前两个字符表示职业,后三个字符表示子职业。 你很少需要直接检查这些代码。 相反,要捕捉相应的 Python 异常类型(列在“异常”栏)。 当你需要区分同一例外类型内的特定错误条件时,可以使用SQLSTATE代码,例如区分死锁(40001)和一般连接故障(08S01)。
00级 - 成功完成
| SQLSTATE |
Exception |
描述 |
| 00000 |
没有 |
成功 |
01级 - 警告
| SQLSTATE |
Exception |
描述 |
| 01000 |
Warning |
常规警告 |
| 01001 |
Warning |
游标操作冲突 |
| 01002 |
Warning |
断开错误 |
| 01003 |
DataError |
在 set 函数中消除 NULL 值 |
| 01004 |
DataError |
字符串数据,右截断 |
| 01006 |
Warning |
权限未撤销 |
| 01007 |
Warning |
未授予权限 |
| 01S00 |
Warning |
无效连接字符串属性 |
| 01S01 |
Warning |
行中错误 |
| 01S02 |
Warning |
选项值已更改 |
07类 - 动态SQL错误
| SQLSTATE |
Exception |
描述 |
| 07001 |
编程错误 |
参数数量错误 |
| 07002 |
编程错误 |
COUNT 字段不正确 |
| 07005 |
编程错误 |
预备语句,非光标规范 |
| 07006 |
编程错误 |
受限数据类型属性冲突 |
| 07009 |
编程错误 |
无效描述子索引 |
| 07S01 |
编程错误 |
默认参数的使用无效 |
08类 - 连接例外
| SQLSTATE |
Exception |
描述 |
| 08001 |
操作错误 |
客户端无法建立连接 |
| 08002 |
操作错误 |
正在使用的连接名称 |
| 08003 |
操作错误 |
连接不存在 |
| 08004 |
操作错误 |
服务器拒绝了连接 |
| 08007 |
操作错误 |
交易期间的连接失败 |
| 08S01 |
操作错误 |
通信链接失败 |
第21类——基数违规
| SQLSTATE |
Exception |
描述 |
| 21S01 |
编程错误 |
插入值列表与列列表不匹配 |
| 21S02 |
编程错误 |
派生表的程度与列列表不匹配 |
类别22 - 数据异常
| SQLSTATE |
Exception |
描述 |
| 22001 |
DataError |
字符串数据,右截断 |
| 22002 |
DataError |
指示符变量是必需的,但未提供 |
| 22003 |
DataError |
数值范围之外 |
| 22007 |
DataError |
日期/时间格式无效 |
| 22008 |
DataError |
日期/时间字段溢出 |
| 22012 |
DataError |
除以零 |
| 22015 |
DataError |
间隔字段溢出 |
| 22018 |
DataError |
强制转换规范的字符值无效 |
| 22019 |
DataError |
转义字符无效 |
| 22025 |
DataError |
无效转义序列 |
| 22026 |
DataError |
字符串数据,长度不匹配 |
第23类 - 完整性约束违规
| SQLSTATE |
Exception |
描述 |
| 23000 |
完整性错误 |
完整性约束违规(一般) |
类别24 - 无效光标状态
| SQLSTATE |
Exception |
描述 |
| 24000 |
内部错误 |
游标状态无效 |
第25类 - 无效交易状态
| SQLSTATE |
Exception |
描述 |
| 25000 |
操作错误 |
无效交易状态 |
| 25S01 |
操作错误 |
交易状态未知 |
| 25S02 |
操作错误 |
交易仍然有效 |
| 25S03 |
操作错误 |
交易被回滚 |
第28类 - 无效授权规范
| SQLSTATE |
Exception |
描述 |
| 28000 |
操作错误 |
授权规范无效(登录失败) |
类别34 - 光标名称无效
| SQLSTATE |
Exception |
描述 |
| 34000 |
编程错误 |
无效的游标名称 |
3C 类 - 重复光标名称
| SQLSTATE |
Exception |
描述 |
| 3C000 |
编程错误 |
重复的游标名称 |
3D类 - 目录名称无效
| SQLSTATE |
Exception |
描述 |
| 3D000 |
编程错误 |
无效的目录名称 |
3F类 - 模式名称无效
| SQLSTATE |
Exception |
描述 |
| 3F000 |
编程错误 |
无效的架构名称 |
40类 - 事务回滚
| SQLSTATE |
Exception |
描述 |
| 40001 |
操作错误 |
串行化失败(死锁) |
| 40002 |
操作错误 |
完整性约束违规导致回滚 |
| 40003 |
操作错误 |
语句完成未知 |
42类 - 语法错误或访问规则违规
| SQLSTATE |
Exception |
描述 |
| 42000 |
编程错误 |
语法错误或访问冲突 |
| 42S01 |
编程错误 |
基表或视图已存在 |
| 42S02 |
编程错误 |
找不到基表或视图 |
| 42S11 |
编程错误 |
索引已存在 |
| 42S12 |
编程错误 |
找不到索引 |
| 42S21 |
编程错误 |
列已存在 |
| 42S22 |
编程错误 |
找不到列 |
44类——带有检查选项违规
| SQLSTATE |
Exception |
描述 |
| 44000 |
完整性错误 |
WITH CHECK OPTION 冲突 |
HY类——CLI特异性疾病
| SQLSTATE |
Exception |
描述 |
| HY000 |
DatabaseError |
常规错误 |
| HY001 |
操作错误 |
内存分配错误 |
| HY003 |
编程错误 |
应用程序缓冲区类型无效 |
| HY004 |
编程错误 |
SQL 数据类型无效 |
| HY007 |
编程错误 |
未准备好关联的语句 |
| HY008 |
操作错误 |
操作已取消 |
| HY009 |
编程错误 |
无效使用 null 指针 |
| HY010 |
编程错误 |
函数序列错误 |
| HY011 |
编程错误 |
无法立即设置属性 |
| HY012 |
编程错误 |
无效的交易操作代码 |
| HY013 |
操作错误 |
内存管理错误 |
| HY014 |
操作错误 |
把手数量限制超过 |
| HY015 |
编程错误 |
没有可用的游标名称 |
| HY016 |
编程错误 |
无法修改实现行描述符 |
| HY017 |
编程错误 |
自动分配描述符句柄的无效使用 |
| HY018 |
操作错误 |
服务器拒绝了取消请求 |
| HY019 |
编程错误 |
非字符和非二元数据分段发送 |
| HY020 |
DataError |
尝试连接空值 |
| HY021 |
编程错误 |
描述符信息不一致 |
| HY024 |
编程错误 |
属性值无效 |
| HY090 |
编程错误 |
字符串或缓冲区长度无效 |
| HY091 |
编程错误 |
无效描述符字段标识符 |
| HY092 |
编程错误 |
无效属性/选项标识符 |
| HY095 |
编程错误 |
功能类型超出范围 |
| HY096 |
编程错误 |
无效信息类型 |
| HY097 |
编程错误 |
列型超出范围 |
| HY098 |
编程错误 |
望远镜类型超出范围 |
| HY099 |
编程错误 |
可消除类型超出范围 |
| HY100 |
编程错误 |
范围外的唯一性选项类型 |
| HY101 |
编程错误 |
准确度选项类型范围不足 |
| HY103 |
编程错误 |
无效检索码 |
| HY104 |
编程错误 |
精度或小数位数值无效 |
| HY105 |
编程错误 |
参数类型无效 |
| HY106 |
编程错误 |
取物类型超出范围 |
| HY107 |
编程错误 |
行值超出范围 |
| HY109 |
编程错误 |
光标位置无效 |
| HY110 |
编程错误 |
无效驱动补全 |
| HY111 |
编程错误 |
无效书签值 |
| HYC00 |
NotSupportedError |
未实现可选功能 |
| HYT00 |
操作错误 |
已超时 |
| HYT01 |
操作错误 |
超过连接超时时间 |
类别 IM - 司机管理员错误
| SQLSTATE |
Exception |
描述 |
| IM001 |
接口错误 |
驱动程序不支持此函数 |
| IM002 |
接口错误 |
未找到数据源名称 |
| IM003 |
接口错误 |
无法加载指定的驱动程序 |
| IM004 |
接口错误 |
驱动程序的 SQLAllocHandle 在 SQL_HANDLE_ENV 失败 |
| IM005 |
接口错误 |
驱动程序的 SQLAllocHandle 在 SQL_HANDLE_DBC 失败 |
| IM006 |
接口错误 |
Driver's SQLSetConnectAttr failed |
| IM007 |
接口错误 |
未指定数据源或驱动 |
| IM008 |
接口错误 |
对话失败 |
| IM009 |
接口错误 |
无法加载翻译 DLL |
| IM010 |
接口错误 |
数据源名称太长 |
| IM011 |
接口错误 |
驱动程序名称太长 |
| IM012 |
接口错误 |
DRIVER 关键字语法错误 |
| IM014 |
接口错误 |
无效DSN |
| IM015 |
接口错误 |
文件数据源损坏 |
常见的SQL Server错误编号
除了 SQLSTATE,SQL Server 还在括号内提供原生错误编号。 这些是你在应用代码中最容易遇到的错误。 围绕错误1205(死锁)和瞬态连接错误(参见 重试逻辑)构建重试逻辑。
| 错误 |
消息模式 |
解决方案 |
| 208 |
对象名称无效 |
确认该表或视图的存在,并检查模式资格。 |
| 547 |
约束冲突 |
外键或校验约束失败。 |
| 2627 |
唯一约束违背 |
插入了一个重复的键值。 |
| 2601 |
唯一索引违规 |
索引中存在一个重复键。 |
| 4060 |
无法打开数据库 |
数据库不存在,或者访问被拒绝。 |
| 18456 |
登录失败 |
身份验证失败。 核查资质。 |
| 1205 |
死锁受害者 |
该事务已回滚。 重试操作。 |
症状到异常快速引用
请使用此表将常见症状映射到你应捕捉的异常类型:
| 症状 |
Exception |
可能的原因 |
| “用户登录失败” |
OperationalError |
错误的凭证或用户没有映射到数据库。 |
| “客户无法建立连接” |
OperationalError |
服务器无法访问,防火墙或DNS问题。 |
| “暂停结束了” |
OperationalError |
查询或连接超时。 增加超时或优化查询。 |
| “无效对象名称” |
ProgrammingError |
表格不存在,模式也没有指定。 |
| “语法错误” |
ProgrammingError |
SQL 语法错误。 在SSMS中测试查询。 |
| “参数数量错误” |
ProgrammingError |
参数数量和占位符不匹配。 |
| “主密钥违规” |
IntegrityError |
复制密钥。
MERGE使用或检查后再插入。 |
| “外来密钥的违规” |
IntegrityError |
引用的行不存在。 先插入父级。 |
| “交易陷入僵局” |
OperationalError (错误1205) |
锁的争夺。 实现重试逻辑。 |
| “字符串或二进制数据会被截断” |
DataError |
值超过列长。 检查数据或增加列大小。 |
| “皈依失败” |
DataError |
类型不匹配。 使用正确的Python类型来表示列。 |
| “未知关键词” |
ConnectionStringParseError |
连接字符串 关键字中的拼写错误。 |
| “Callproc不支持” |
NotSupportedError |
改用 cursor.execute("EXECUTE ...")。 |
最佳做法
- 在处理泛泛的例外之前,先发现具体的例外情况。 按最具体的(
IntegrityError)到最不具体Error的()排序。
-
数据修改操作时务必处理IntegrityError 。 约束违规在正常操作中是预期的(例如,用户试图创建重复的用户名)。
-
记录完整的错误上下文 以便排查。 该例外暴露
driver_error (稳定文本,SQLSTATE派生文本)和 ddbc_error (服务器端消息)。 两者都记录;分类。driver_error
- 为瞬态错误(连接失败、死锁)实现重试逻辑。 参见 重试逻辑。
- 在例外处理程序中使用rollback()来清理失败的事务。 如果没有显式回滚,连接会保持交易失败状态。
相关内容