pyodbc查询SQL Server时cursor.fetchall()死锁,如何正确恢复?
死锁后正确的恢复方式:重新执行完整查询流程
当遇到fetchall()抛出死锁异常的情况,必须重新执行cursor.execute(),再调用fetchall(),不能只单独重试fetchall()。
原因很明确:SQL Server判定你的查询进程为死锁受害者后,会直接终止该查询的数据库端执行上下文。哪怕之前execute()调用成功,也只是完成了查询请求的发送,数据库并没有保留可用的结果集(或已准备的结果集被销毁),此时cursor已经没有有效数据可读取,单独重试fetchall()只会持续报错。
正确的重试逻辑需要包含完整的查询流程,示例代码如下:
import pyodbc # 假设self.cursor已完成初始化 max_retries = 3 retry_count = 0 results = None while retry_count < max_retries: try: self.cursor.execute(sql, *values) self.rowcount = self.cursor.rowcount results = self.cursor.fetchall() break # 成功获取结果,退出重试循环 except pyodbc.Error as e: # 识别死锁错误(错误码1205) if '1205' in str(e.args[0]): retry_count += 1 print(f"遭遇死锁,正在重试第{retry_count}次") else: # 非死锁异常直接抛出 raise if not results: raise RuntimeError("经过3次重试后仍无法完成查询,死锁问题持续存在")
需要注意:重试只是临时恢复手段,长期来看应该排查死锁根源——比如通过SQL Server死锁图分析资源竞争情况,优化查询语句、添加合适索引,或调整事务隔离级别(如启用READ COMMITTED SNAPSHOT)来降低死锁发生率。
内容的提问来源于stack exchange,提问作者Sergey Nudnov
相关产品推荐
相关产品推荐

