SQLAlchemy调用SQL Server存储过程无数据写入问题求助
首先看你的代码,我注意到一个非常可能导致问题的核心点:存储过程调用时的参数传递方式错误。
你在代码里用了:
session.execute('EXEC finish_order %a' % ref)
这里的%a是Python的字符串格式化符号,它会调用repr()处理你的ref变量。比如如果ref是字符串'REF0000001',%a会把它转换成'\'REF0000001\''(带单引号的字符串),这就导致存储过程接收到的参数是带额外引号的,自然查询不到你之前插入的订单数据——而你在SSMS里手动执行时,肯定是直接传递REF0000001(不带额外引号),所以能正常工作。
除了这个核心问题,还有几个可以优化和排查的点:
1. 修正存储过程的参数传递方式
永远不要用字符串拼接传递SQL参数,这不仅会导致参数解析错误,还会引入SQL注入风险。改用SQLAlchemy的参数绑定方式:
session.execute('EXEC finish_order :ref', {'ref': ref})
这种方式会由SQLAlchemy正确处理参数的类型和格式,确保存储过程收到的是正确的REF0000001值。
2. 检查事务异常处理逻辑
你的except块里写的reraise是无效的Python语法,应该改为raise来重新抛出异常,否则如果插入过程中出现异常,你可能看不到错误信息,误以为插入成功了:
except Exception as e: session.rollback() raise # 重新抛出异常,便于排查问题
3. 关于“插入未完成”的疑问
你担心的“插入操作尚未完成就调用存储过程”其实不太可能:第一个会话已经执行了session.commit(),这会确保所有变更都提交到数据库,并且对其他会话可见(除非你的数据库设置了特殊的隔离级别,但你用的是SERIALIZABLE,提交后其他会话肯定能读到)。你加的time.sleep(1)其实是多余的,完全可以去掉。
4. 验证存储过程的执行日志
如果修正参数传递后还是有问题,可以在存储过程里添加日志(比如插入到一个日志表记录输入参数和执行步骤),或者在代码里捕获存储过程的执行结果,确认存储过程是否真的找到了源数据:
result = session.execute('EXEC finish_order :ref', {'ref': ref}) # 查看存储过程的输出(如果有) for row in result: print(row)
总结
最可能的原因就是参数传递时的%a导致参数格式错误,先修正这个问题,应该就能解决存储过程无输出的问题。如果还有问题,再检查异常处理和存储过程的执行日志。
内容的提问来源于stack exchange,提问作者Gia Duong Duc Minh

