IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    一次启用事务 begin 没有 commit 的事故

    Qianyugang发表于 2023-06-16 02:02:24
    love 0

    最近在公司接到了一个工单,表象是运营人员在配置一个表单的时候执行一个接口请求,所有的日志和返回都是正确,但是 update 和 insert 语句都没有执行,日志系统却都追踪到执行了此语句。更奇怪的是,这个接口的前半部分都执行成功,后半部分都失败了。如下中语句1、语句2、语句3、都成功了。语句4、语句5、语句6都失败了。

    问题

    伪代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    $parameters = [];
    $db->select;//语句1
    $db->insert;//语句2
    $db->update;//语句3
    $db->begin;
    $re = $this->judge(parameters)
    if($re == false){
    return false;
    }
    $db->commit;
    $db->update;//语句5
    $db->insert;//语句6
    return true;
    function judge(parameters){
    if ( $parameters[xx] = null){
    $db->update;//语句4
    return true;
    }
    }

    排查

    拿到这个问题按照经验来讲,就是通过几个方面来排查:

    1. 代码问题,是否有bug
    2. 是否启用了事务,执行失败导致回滚。
    3. 是否是因为数据库配置了主从,update 和 insert 的主表,select 的从表,但是主从不一致。

    随后和架构师以及运维沟通,排除了3,数据库日志都显示正常。那就去排查2,发现虽然代码中有一个事务,但是并不影响主流程的执行。1排查了半天,由于是老代码,且写代码的人离职了,所以并不能仔细的追踪到问题点。

    于是就造了一些数据,把线上的拉到本地执行,发现了问题的真正所在:1+2一起造成了这次bug。

    原因

    在语句3之后开启了事务,参数 $parameters[xx] = null 的时候,加了一个判断,问题是在判断之后,直接返回了个true,也就是说此时开启了事务,随后所有的语句都会掉到这个事务中,由于一直没有commit,语句4和语句4以后的sql都得不到执行。在长时间没有执行的情况下,sql语句会自动回滚。相当于语句4和语句4以后的sql都没有执行。但是只从代码上看,语句5、语句6的确是执行到了。

    所以 实际上,本次事故,的原因是有两个:

    • 第一是代码问题。
    • 第二是我们的日志系统没有追中到事务的执行,只是单纯的记录了sql的执行。

    修复

    直接修复代码即可。使用事务,一定要完整且闭合。



沪ICP备19023445号-2号
友情链接