SQLite 外层回滚后数据仍存在:嵌套 with connection 提前提交的复现与修复
导入程序先写入批次记录,再调用公共函数写明细,最后校验失败抛出异常。代码外面明明套了 with connection,重查数据库却发现批次和明细都还在。遇到这种情况,先沿调用链检查谁执行了提交,尤其是公共函数里的第二层 with connection。 下面是可执行的缩小案例,不对应某个生产事故。适用于 Python
Tag
包含这个标签的文章。
导入程序先写入批次记录,再调用公共函数写明细,最后校验失败抛出异常。代码外面明明套了 with connection,重查数据库却发现批次和明细都还在。遇到这种情况,先沿调用链检查谁执行了提交,尤其是公共函数里的第二层 with connection。 下面是可执行的缩小案例,不对应某个生产事故。适用于 Python
场景与现象 后台有一个商品标题搜索框,产品约定是“包含输入文字”。运营想找标题里带 50% 的商品,却同时搜到了 500g;输入 _ 后,大部分非空标题都出现在结果里。接口已经使用 SQL 参数绑定,代码审查也没有发现字符串拼接。 下面复现的是搜索语义错误:输入中的特殊字符进入了 LIKE 模式。本文以 Python
订单表有三条记录,导出任务正常结束,却只生成一条。没有 SQL 异常,也没有过滤条件变化。检查循环体后发现:遍历订单的游标,又被用来查询客户名称。 这类漏行先查游标的使用范围。增加超时或重试次数不会修复已经被替换的结果集。 适用场景与现象 本文针对 Python 标准库 sqlite3:外层逐条读取订单,内层查询关联信
接口返回成功,主表记录也还在,但关联明细突然清空。遇到这种现象,先找到实际执行的 SQL:如果所谓“更新”用了 INSERT OR REPLACE,就要沿着删除路径排查。 本文用一个订单与明细模型复现问题,再把写入改成有明确冲突目标的 UPSERT。实验只使用内存数据库,不连接生产服务。 适用场景与现象 适用于 SQL
接口先查询计数器,再更新它。连接已经设置 timeout=5,更新却几乎立即返回 database is locked。把超时调到 30 秒仍然失败,而同一条 SQL 在新连接上可以成功。此时要检查失败连接是否持有旧的读快照。 本文针对 Python 3.12+ 标准库 sqlite3、本机文件数据库、WAL 模式和独
订单明细表已经写了 REFERENCES orders(id),导入程序却能插入不存在的订单号。更容易误判的情况是:初始化脚本设置过 PRAGMA foreign_keys = ON,接口仍然产生孤儿明细。 这时先确认写入连接的状态。SQLite 的外键执行开关属于连接;迁移连接开启,不代表接口、后台任务和临时导入脚本
适用场景与现象 配置表按租户和作用域保存覆盖项:scope_id 有值表示某个具体作用域,为 NULL 表示租户默认配置。业务要求每个租户只能有一条默认配置,每个具体作用域也只能有一条。 表上已经有 UNIQUE (tenant_id, scope_id),压测后却出现两条默认配置。读取接口用 LIMIT 1 暂时掩盖
订单明细增加退款展示后,报表的销售额突然变大。单独查订单金额正确,单独查退款也正确,只有合并查询对不上。此时先检查关联后的数据粒度:一张订单同时对应多条商品明细和多条退款时,两组明细会组合成多行,最后的 SUM 会把同一金额累计多次。 本文以 PostgreSQL 17 为语义基准,用一套可复现数据定位问题,再把查询改
场景:有待处理订单,补偿任务却扫不到 补偿任务从订单表里找出“尚未有成功回执”的订单。原先使用 NOT IN (SELECT order_id ...),导入一条未关联订单的回执后,任务突然返回零行,接口没有报错,查询耗时也正常。 下面是隔离复现,不代表真实生产事故。SQL 按 PostgreSQL 17 编写,使用会
适用场景 本文适用于 PostgreSQL 13 及以上版本的生产库:为了避免普通 CREATE INDEX 长时间阻塞写入,运维或开发人员改用 CREATE INDEX CONCURRENTLY,但命令执行数十分钟后失败、被取消,或者发布系统超时退出。重新执行时又提示索引已存在,查询计划却仍然走顺序扫描。 本文重点处