MySQL事务中START TRANSACTION位置不同导致SELECT返回空记录原因求解
问题原因分析
核心可能性1:UPDATE语句执行出错未被捕获,导致连接状态异常
你遇到的现象最常见的诱因是第一条UPDATE语句本身执行失败,你没有做错误校验,导致后续查询受连接错误状态影响返回空,对应逻辑如下:
- 第一种写法执行流程:
- 开启事务
- 执行UPDATE语句时触发错误(最常见的问题:
ps_category是PrestaShop的系统表,原生不存在key字段,你可能是把关联字段名写错了;也可能是字段类型不匹配、表名拼写错误等) - 数据库连接进入错误状态,你没有调用错误检查方法排查,直接执行SELECT查询,数据库驱动会直接返回空结果集
- 最终提交事务时,事务已经因为SQL错误被隐式回滚
- 第二种写法执行流程:
- 先执行错误的UPDATE语句,同样触发错误,连接进入错误状态
- 执行
START TRANSACTION开启事务的操作会重置数据库连接的错误状态,清空之前的报错标记 - 此时再执行SELECT查询,连接状态正常,所以可以正常返回数据
- 提交空事务,无任何影响
你可以先打印UPDATE语句执行后的错误信息验证这个判断,示例代码:
$updateRes = $this->db->execute("你的UPDATE语句"); if (!$updateRes) { var_dump($this->db->getError()); // 这里会输出具体的SQL错误原因 }
核心可能性2:全局查询过滤规则的影响
如果确认UPDATE语句执行成功,那第二个可能的原因是你的数据库ORM层配置了全局查询条件:
- 比如框架默认给
ps_category的所有查询加了WHERE active = 1的过滤条件 - 第一种写法中,UPDATE语句匹配到了所有分类记录,把
active都更新为0,后续查询走全局过滤就会返回空 - 第二种写法中,UPDATE先执行修改,但是开启事务后你的查询逻辑临时跳过了全局过滤,所以可以正常返回所有记录
其他低概率原因
- 你的数据库表使用了不支持事务的MyISAM引擎:事务内执行UPDATE会锁表,后续查询因为锁等待超时返回空,而UPDATE放在事务外执行完自动释放锁,后续查询可以正常执行
- 事务隔离级别配置异常:极少数情况下自定义的事务隔离级别会导致当前事务内的修改不可见,可通过
SELECT @@transaction_isolation;检查隔离级别配置
内容的提问来源于stack exchange,提问作者abrfra
相关产品推荐
相关产品推荐

