存在和不存在的数据库行

主要观点:在将应用从 Python 升级到 Django 5 时,在 QA 环境中遇到一个神秘的IntegrityError异常,即对象无法保存因为主键已存在于数据库中,经过一系列排查和实验,最终发现是 Django 模型定义和实际数据库架构因历史原因漂移,主键类型不一致导致,且 Django 5.0 中关于过滤溢出整数值的规定使得问题暴露。
关键信息:

  • 在开发环境工作正常,部署到 QA 环境后出现问题,错误信息为IntegrityError
  • 代码中未手动分配id,只是查询并更新现有记录,但 Django 却尝试插入新行。
  • 多人从不同角度排查,发现只有部分记录有问题,且仅在 Django 中出现,在 Postgres 中正常。
  • 查看 Django 使用的查询集发现为空,导致认为记录是新的应插入而不是更新。
  • 发现 Django 模型定义和实际数据库架构中主键类型不一致,有问题的记录idint范围外。
  • 回顾 Django 5.0 发行说明,其中提到过滤溢出整数值的规定与当前问题相关。
    重要细节:
  • 代码示例为object = models.Model.filter(property1=value).get()\nobject.property2 = method_result()\nobject.save()
  • 尝试各种方法来缩小问题范围,如简化代码、强制更新等。
  • 同事尝试获取不同id的记录,发现只有部分idint范围外的记录有问题。
  • Django 5.0 之前版本允许“不可能”的比较,而 5.0 版本强制内部正确性拒绝了该比较。
阅读 29
0 条评论