Discord Bot Python脚本在Ubuntu 20.04 VPS运行报类型错误 Windows端正常
问题核心诱因
- 报错和业务代码逻辑无关,是两个环境的SQLite驱动行为差异,叠加数据库内的历史脏数据共同导致的:
- SQLite采用动态类型存储机制,哪怕建表时把字段声明为INTEGER类型,也支持存入TEXT形式的数值,驱动会严格按照数据实际的存储类返回对应Python类型,不会强制校验类型一致性。
- Windows官方Python安装包内置的SQLite核心版本更高,对具备INTEGER列亲和性的字段,读取时会自动将TEXT存储的数值字符串隐式转换为Python int;而Ubuntu 20.04下Python 3.9绑定的SQLite版本严格遵循存储类返回规则,存的是TEXT就直接返回str,不做隐式类型转换。
- 你在Windows端长期运行时,因为一直用f-string拼接SQL传值,已经在
misija.sqlite数据库的userid、laikasmisija列里混入了TEXT类型的数值。本地运行时靠驱动的隐式转换兜底,从来没暴露这个问题,部署到VPS上驱动不再做隐式转换,直接把str类型的值传给Python,才会触发str - int的类型运算报错。
无需全量修改代码的解决方案
完全不需要逐行给所有变量加int()转换,有两种低工作量的方案可选:
- 最快适配方案(改几行连接代码即可)
写一个通用的数据库连接函数,全局注册INTEGER类型的转换规则,让所有数据库连接读出来的数字字段自动转成int,完全复现Windows端的隐式转换行为。只需要把脚本里所有原来手写的sqlite3.connect()语句替换成调用这个函数的代码即可,业务逻辑代码完全不用改动:
原来的连接代码import sqlite3 from sqlite3 import PARSE_DECLTYPES def get_db_conn(db_path): # 注册INTEGER类型的自动转换规则,不管底层存的是文本还是数值,都转成Python int sqlite3.register_converter("INTEGER", lambda value: int(value.decode()) if value else 0) conn = sqlite3.connect(db_path, detect_types=PARSE_DECLTYPES) return conndb=sqlite3.connect('misija.sqlite')替换成db = get_db_conn('misija.sqlite')即可,全脚本改动量不超过10行。 - 一劳永逸方案(一次性修复数据库脏数据)
直接连接VPS上的misija.sqlite数据库,执行一段强制类型转换的SQL,把表内混入的TEXT类型数值统一转成标准INTEGER存储,后续驱动读出来就会直接返回int类型,连代码都不用改:
执行完成后,全表的数值字段就和Windows端的预期行为一致了,不会再触发类型错误。-- 修复misijos表内的类型不统一问题 UPDATE misijos SET laikasmisija = CAST(laikasmisija AS INTEGER); UPDATE misijos SET userid = CAST(userid AS INTEGER);
补充说明:你当前所有用f-string拼接SQL的写法本身存在SQL注入风险,后续如果有时间可以逐步替换为参数化查询,从根源上避免混类型存值的问题,但这部分不属于当前报错的必须修改范围。
内容的提问来源于stack exchange,提问作者Kevinas
相关产品推荐
相关产品推荐

